Repository: wimglenn/advent-of-code-data

Issue:
Transform for single line numberic data
recently ([2021 day 6](https://adventofcode.com/2021/day/6) and [2021 day 7](https://adventofcode.com/2021/day/6)) there have been inputs that are single line numeric lists eg: `1,2,3,4,5`

This API doesn't currently have a quick way of parsing this data.

I would suggest the following modification to the `aocd.transforms.numbers` function to keep the old behavior but also allow quick parsing of numeric lists with arbitrary separators. 

```python3
_missing = object()

def numbers(data, sep=_missing):
    if sep is _missing:
        return [int(n) for n in data.splitlines()]
    else:
        return [int(n.strip()) for n in data.strip().split(sep)]
```

eg:
```python3
>>> from aocd.transforms import numbers

>>> data = "1\n2\n3\n4\n5"
>>> numbers(data) # current behavior
[1, 2, 3, 4, 5]

>>> data = "1,2,3,4,5"
>>> numbers(data, sep=',') # new behavior (single char)
[1, 2, 3, 4, 5]

>>> data = '1hello2hello3hello4hello5'
>>> numbers(data, sep='hello') # new behavior (multi char)
[1, 2, 3, 4, 5]

>>> data = "1 2  3\n 4 \t 5"
>>> numbers(data, sep=None) # new behavior (whitespace)
[1, 2, 3, 4, 5]
```

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/wimglenn/advent-of-code-data/pull/70?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn) Report
> Merging [#70](https://codecov.io/gh/wimglenn/advent-of-code-data/pull/70?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn) (1e970d5) into [master](https://codecov.io/gh/wimglenn/advent-of-code-data/commit/e5fb37d9d2f29679909fdc8c9405f9f76ec4ddb7?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn) (e5fb37d) will **decrease** coverage by `0.16%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/wimglenn/advent-of-code-data/pull/70/graphs/tree.svg?width=650&height=150&src=pr&token=F9aAnYNHdu&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn)](https://codecov.io/gh/wimglenn/advent-of-code-data/pull/70?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn)

```diff
@@            Coverage Diff             @@
##           master      #70      +/-   ##
==========================================
- Coverage   92.08%   91.91%   -0.17%     
==========================================
  Files          23       24       +1     
  Lines        1907     1930      +23     
  Branches      164      169       +5     
==========================================
+ Hits         1756     1774      +18     
- Misses        123      127       +4     
- Partials       28       29       +1     
```


| [Impacted Files](https://codecov.io/gh/wimglenn/advent-of-code-data/pull/70?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn) | Coverage Δ | |
|---|---|---|
| [aocd/\_\_init\_\_.py](https://codecov.io/gh/wimglenn/advent-of-code-data/pull/70/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn#diff-YW9jZC9fX2luaXRfXy5weQ==) | `93.87% <100.00%> (-6.13%)` | :arrow_down: |
| [aocd/transforms.py](https://codecov.io/gh/wimglenn/advent-of-code-data/pull/70/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn#diff-YW9jZC90cmFuc2Zvcm1zLnB5) | `100.00% <100.00%> (ø)` | |
| [tests/test\_transforms.py](https://codecov.io/gh/wimglenn/advent-of-code-data/pull/70/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn#diff-dGVzdHMvdGVzdF90cmFuc2Zvcm1zLnB5) | `100.00% <100.00%> (ø)` | |
| [aocd/runner.py](https://codecov.io/gh/wimglenn/advent-of-code-data/pull/70/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn#diff-YW9jZC9ydW5uZXIucHk=) | `94.24% <0.00%> (-1.05%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/wimglenn/advent-of-code-data/pull/70?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/wimglenn/advent-of-code-data/pull/70?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn). Last update [e5fb37d...1e970d5](https://codecov.io/gh/wimglenn/advent-of-code-data/pull/70?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=wim+glenn).


Patch:
diff --git a/README.rst b/README.rst
index 53cecde..8340df0 100644
--- a/README.rst
+++ b/README.rst
@@ -39,7 +39,7 @@ There are currently two convenience transforms (maybe more to come later):
 .. code-block:: python
 
    from aocd import lines  # like data.splitlines()
-   from aocd import numbers  # like [int(n) for n in data.splitlines()]
+   from aocd import numbers  # uses regex pattern -?\d+ to extract integers from data
 
 If all that sounds too magical, there is a simple getter function to just return your raw data.
 
diff --git a/aocd/__init__.py b/aocd/__init__.py
index 5dd8d78..0fc7c80 100644
--- a/aocd/__init__.py
+++ b/aocd/__init__.py
@@ -45,7 +45,7 @@ __all__ = [
     "PuzzleUnsolvedError",
     "AOC_TZ",
 ]
-__all__.extend(transforms.__all__)
+__all__ += transforms.__all__
 
 
 class Aocd(object):
diff --git a/aocd/transforms.py b/aocd/transforms.py
index f711ff1..f25ef5f 100644
--- a/aocd/transforms.py
+++ b/aocd/transforms.py
@@ -6,10 +6,23 @@ Every function here needs to accept one positional argument and return the
 
 __all__ = ["lines", "numbers"]
 
+import re
+
 
 def lines(data):
     return data.splitlines()
 
 
 def numbers(data):
-    return [int(n) for n in data.splitlines()]
+    result = []
+    for line in data.splitlines():
+        matches = [int(n) for n in re.findall(r"-?\d+", line)]
+        if matches:
+            result.append(matches)
+    if all(len(n) == 1 for n in result):
+        # flatten the list if there is always 1 number per line
+        result = [n for [n] in result]
+    if len(result) == 1:
+        # un-nest the list if there is only one line
+        [result] = result
+    return result


Test patch:
diff --git a/tests/test_transforms.py b/tests/test_transforms.py
new file mode 100644
index 0000000..d40d9ce
--- /dev/null
+++ b/tests/test_transforms.py
@@ -0,0 +1,27 @@
+from aocd.transforms import numbers
+
+
+def test_get_numbers_csv():
+    txt = "1,2,3\n"
+    assert numbers(txt) == [1, 2, 3]
+
+
+def test_get_numbers_whitespace():
+    txt = "1 2 -3"
+    assert numbers(txt) == [1, 2, -3]
+
+
+def test_get_numbers_ragged():
+    txt = "1,-2,3\n-4,5\n"
+    assert numbers(txt) == [[1, -2, 3], [-4, 5]]
+
+
+def test_get_numbers_ptp():
+    txt = """
+        68,788 -> 68,875
+        858,142 -> 758,142
+    """
+    assert numbers(txt) == [
+        [68, 788, 68, 875],
+        [858, 142, 758, 142],
+    ]