Repository: wimglenn/advent-of-code-data (language: python)

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/7)) 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 / hints:

Fix 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 @@
     "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 @@
 
 __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],
+    ]