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] -- https://mail.python.org/mailman/listinfo/python-list