get the sum of differences between integers in a list
Peter Otten
__peter__ at web.de
Fri Sep 23 06:07:35 EDT 2016
Daiyue Weng wrote:
> i, I am new to the advanced python techniques, and by studying your code,
> I understand that when calling grouped function with values[1, 2, 3, 6, 8,
> 9, 10, 11, 13, 17, 19],
>
> tee(values, 3) generated 3 iterators shared values
>
> left contains [1, 2, 3, 6, 8, 9, 10, 11, 13, 17, 19],
> mid contains [1, 2, 3, 6, 8, 9, 10, 11, 13, 17, 19],
> right contains [1, 2, 3, 6, 8, 9, 10, 11, 13, 17, 19].
>
> passing them into zip(),
>
> chain([None], left) generated,
>
> [1, 2, 3, 6, 8, 9, 10, 11, 13, 17, 19]
>
> chain(islice(right,1,None), [None]) generated,
>
> [2, 3, 6, 8, 9, 10, 11, 13, 17, 19]
>
> zip(chain([None], left), mid, chain(islice(right, 1, None), [None])
> generated triples with,
>
> [(1,1,2), (2,2,3), (3,3,6),...,(17,17,19)]
>
> The question is how does triples work in groupby(triples, lonely)?
> especially within lonely(triple)?
Consecutive triples with the same value for lonely(triple) are put into the
same group. A smaller example:
values = [1, 2, 4, 6, 8, 9]
gives the group keys (True == lonely)
[False, False, True, True, False, Fale]
and results in the groups
not loneley: [1, 2]
lonely [4, 6]
not lonely: [8, 9]
> e.g. for first 3 tuples (1,1,2), (2,2,3), (3,3,6), lonely(triple) will
> generated
>
> False, False, True
>
> how does this result work in groupby()?
>
> and what's the necessariness of
>
> if left is not None and value - left == 1:
> return False
If you look only at one side the groups will become
no gap on the right: [1]
gap on the right: [2, 4, 6]
no gap on the right: [8, 9]
assuming that we declare there's no gap on the right side of the last item.
In code:
>>> from itertools import *
>>> def triples(values):
... a, b, c = tee(values, 3)
... return zip(chain([None], a), b, chain(islice(c, 1, None), [None]))
...
>>> def gap(x, y): return x is not None and y is not None and y - x != 1
...
>>> def values(triples): return [t[1] for t in triples]
...
>>> sample = [1, 2, 4, 6, 8, 9]
>>> [values(g) for k, g in groupby(triples(sample), lambda v: gap(*v[:2])
and gap(*v[1:]))]
[[1, 2], [4, 6], [8, 9]]
I'm lazy, so I continue using triples even though pairs would be sufficient
below.
>>> [values(g) for k, g in groupby(triples(sample), lambda v: gap(*v[1:]))]
[[1], [2, 4, 6], [8, 9]]
We could use a stateful key to start a group every time we see a gap
>>> def make_key():
... group = True
... def key(v):
... nonlocal group
... if gap(*v[:2]): group = not group
... return group
... return key
...
>>> [values(g) for k, g in groupby(triples(sample), make_key())]
[[1, 2], [4], [6], [8, 9]]
but this has the disadvantage(?) that every lonely value lands in a separate
group. Your usecase could then be addressed by checking the groups' lengths:
>>> consecutive = []
>>> other = []
>>> for k, g in groupby(triples(sample), make_key()):
... g = values(g)
... if len(g) == 1: other.extend(g)
... else: consecutive.append(g)
...
>>> consecutive
[[1, 2], [8, 9]]
>>> other
[4, 6]
More information about the Python-list
mailing list