Skip to content

Instantly share code, notes, and snippets.

@samclane
Created September 21, 2020 15:43
Show Gist options
  • Save samclane/ac4ba7665f1d65f8039e16e809be4cc7 to your computer and use it in GitHub Desktop.
Save samclane/ac4ba7665f1d65f8039e16e809be4cc7 to your computer and use it in GitHub Desktop.
from __future__ import annotations
from functools import reduce
from operator import add
from typing import Sequence, Union, Iterable, Any
NumberTypes = (int, float, complex,)
Number = Union[NumberTypes]
NestedSequences = Union[Number, Sequence['NestedSequences']]
def flatten(items, ignore_types=(str, bytes)):
for x in items:
if isinstance(x, Iterable) and not isinstance(x, ignore_types):
yield from flatten(x, ignore_types)
else:
yield x
def deep_add(seq: NestedSequences, start: Any = 0) -> int:
"""
>>> deep_add([1, 2, 3, 4])
10
>>> deep_add([[1, 2, 3], [4, 5, 6]])
21
>>> deep_add([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
36
Bonus 1:
>>> deep_add([(1, 2), [3, {4, 5}]])
15
Bonus 2:
>>> deep_add([[1, 2], [3, 4]], start=2)
12
Bonus 3:
>>> from datetime import timedelta
>>> deep_add([[timedelta(5), timedelta(10)], [timedelta(3)]], start=timedelta(0))
18
"""
flat = list(flatten(seq))
typ = type(flat[0]) if len(flat) else int
if len(flat) == 0:
flat.append(0)
result = reduce(add, flat)
if typ in NumberTypes:
return result + start
else:
return (result + start) / typ(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment