Two different lazy solutions in Python, using the itertools module.
Using itertools.groupby (and accumulate)
from itertools import accumulate, groupbyresult = ( item for _, group in groupby(x, key=lambda n: n < 0) for item in enumerate(accumulate(group), 1))
Using itertools.accumulate with a custom accumulation function
from itertools import accumulatedef sign_count_sum(count_sum, value): count, prev_sum = count_sum same_sign = (prev_sum < 0) is (value < 0) if same_sign: return count + 1, prev_sum + value else: return 1, valueresult = accumulate(x, sign_count_sum, initial=(0, 0))next(result) # needed to skip the initial (0, 0) item
The initial
keyword argument was added in Python 3.8. In earlier versions you can use itertools.chain
to prepend the (0,0)-tuple:
result = accumulate(chain([(0, 0)], x), sign_count_sum)
The output is as expected:
for (i, v), (c, s) in zip(enumerate(x), result): print(f"{i:3} {v:7.3f} {c:3} {s:7.3f}")
0 -0.010 1 -0.010 1 0.003 1 0.003 2 -0.002 1 -0.002 3 0.018 1 0.018 4 0.002 2 0.020 5 0.006 3 0.026 6 -0.012 1 -0.012 7 0.014 1 0.014 8 -0.017 1 -0.017 9 -0.007 2 -0.024 10 0.002 1 0.002 11 0.002 2 0.004 12 -0.004 1 -0.004 13 0.015 1 0.015 14 0.002 2 0.017 15 -0.001 1 -0.001 16 -0.008 2 -0.009 17 0.010 1 0.010 18 -0.018 1 -0.018 19 0.046 1 0.046