Jussi Piitulainen wrote: > breamore...@gmail.com writes: > >> On Monday, June 12, 2017 at 7:33:03 PM UTC+1, José Manuel Suárez Sierra >> wrote: >>> Hello, >>> I am stuck with a (perhaps) easy problem, I hope someone can help me: >>> >>> My problem is: >>> I have a list of lists like this one: >>> [[55, 56, 57, 58, 83, 84, 85, 86, 89, 90, 91, 92, 107, 108, 109, 110, >>> 111, 117, 118, 119, 120, 128, 129, 130, 131, 135, 136, 137, 138, 184, >>> 185, 186, 187, 216, 217, 218, 219, 232, 233, 234, 235, 236, 237, 238, >>> 267, 268, 269, 270, 272, 273, 274, 275], [2, 3, 4, 5, 9, 10, 11, 12, >>> 21, 22, 23, 24, 29, 30, 31, 32, 56, 57, 58, 59, 65, 66, 67, 68, 74, >>> 75, 76, 77, 78, 89, 90, 91, 92, 98, 99, 100, 101, 102, 125, 126, 127, >>> 128, 131, 132, 133, 134, 135]] >>> >>> And what I want is to store some of these datum into another list >>> according to the next conditions: >>> >>> 1. I just want to store data if these values are consecutive (four in >>> four), for instance, for first element I would like to store into the >>> new list: [[[55,58],[83,86],....[n,n+3]]] and so on. >>> >>> I tried something like this: >>> >>> x=0 >>> y=0 >>> while list6[x][y] == list6[x][y+1]-1 and list6[x][y] == >>> list6[x][y+1]-2 and list6[x][y] == list6[x][y+1]-3 or >>> list6[x][0]: >>> >>> list7.append(list6[x][y]) >>> list7.append(list6[x][y+3]) >>> y = y+1 >>> if (list6[x][y])%(list6[x][len(list6[x])-1]) == 0: >>> x= x+1 >>> >>> if len(list6[x]) == x and len(list6[x][y]) == y: >>> break >>> >>> >>> It does not work >>> >>> I appreciate your help >>> Thank you >> >> Perhaps use the recipe for consecutive numbers from here >> https://docs.python.org/2.6/library/itertools.html#examples It will >> have to be modified for Python 3, I'll leave that as an exercise. > > What a clever idea. Pity it's gone in newer documentation. (By the "it" > in the previous sentence I refer only to the idea of grouping by the > difference to the index in the original sequence, and by "gone" only to > the fact that I didn't see this example at the corresponding location > for Python 3.6, which I found by replacing the 2 in the URL with 3. > Perhaps the idea is preserved somewhere else?) > > Anyway, I've adapted it to Python 3, and to an analysis of the problem > at hand - mainly the problem that the OP finds themselves _stuck_ with > their spec and their code, as quoted above. Hope it helps. > > What follows, follows. > > # The big idea is to define (auxiliary) functions. It's not an > # advanced idea. It's the most basic of all ideas. The experience of > # being stuck comes from trying to see the whole problem at once. > > # Ok, familiary with standard ways of viewing things helps. But that > # is just the flip side of breaking problems into manageable parts: > # past experience suggests that some kinds of parts are more useful, > # more composable into a solution, so in standard libraries. > > # One subproblem is to group just one list of numbers, then it is easy > # to group every list in a list of such lists. But another subproblem > # is to deal with one group of numbers. There seem to be two concerns: > # a group should consist of consecutive numbers, and a group should > # consist of four numbers - the latter at least is easy enough if the > # group is stored as a list, but what should be done if there are five > # or seven numbers? No idea, but that can be clarified later once the > # components of a solution are untangled into their own functions. > > # The battle cry is: Use def! > > import itertools as it > import operator as op > > def applied(f): > '''Reification of that asterisk - like a really advanced > computer-sciency kind of thing. But see no lambda!''' > def F(args): return f(*args) > return F > > def consequences(data): > '''Lists of consecutive datami, clever idea adapted from > https://docs.python.org/2.6/library/itertools.html#examples''' > for k, group in it.groupby(enumerate(data), applied(op.sub)): > yield [datum for index, datum in group]
Hm, the itertools users' code of honour requires that no intermediate sequences be materialised ;) So: second = op.itemgetter(1) def consequences(data): for k, group in it.groupby(enumerate(data), applied(op.sub)): yield edges(map(second, group)) def isfourlong(pair): min, max = pair return max - min == 3 def edges(items): first = last = next(items) for last in items: pass return [first, last] def ends(sequences): return list(sequences) However, this is infested with for loops. Therefore def consequences(data): groups = map(second, it.groupby(enumerate(data), applied(op.sub))) sans_index = map(functools.partial(map, second), groups) return map(edges, sans_index) and because we want to hide traces that this was written by mere mortals def consequences(data): return map( edges, map( functools.partial(map, second), map(second, it.groupby(enumerate(data), applied(op.sub))) ) ) I don't immediately see what to do about the for loop in edges(), so I'll use the traditional cop-out: Removing the last loop is left as an exercise... > def isfourlong(sequence): > '''True if sequence is of length 4.''' > return len(sequence) == 4 > > def ends(sequences): > '''Collect the endpoints of sequences in a list of 2-lists.''' > return [[sequence[0], sequence[-1]] for sequence in sequences] > > data = [[55, 56, 57, 58, 83, 84, 85, 86, 89, 90, 91, 92, 107, 108, > 109, 110, 111, 117, 118, 119, 120, 128, 129, 130, 131, 135, > 136, 137, 138, 184, 185, 186, 187, 216, 217, 218, 219, 232, > 233, 234, 235, 236, 237, 238, 267, 268, 269, 270, 272, 273, > 274, 275], > > [2, 3, 4, 5, 9, 10, 11, 12, 21, 22, 23, 24, 29, 30, 31, 32, > 56, 57, 58, 59, 65, 66, 67, 68, 74, 75, 76, 77, 78, 89, 90, > 91, 92, 98, 99, 100, 101, 102, 125, 126, 127, 128, 131, 132, > 133, 134, 135]] > > def testrun(): > '''See how many variations can be composed out of the few auxiliary > functions - the problem becomes tame, or at least a bit tamer. > This kind of ad-hoc test suite is very useful, during development, > when at all in doubt.''' > print('groups in both lists:') > print(list(consequences(data[0]))) > print(list(consequences(data[1]))) > # note the calls to list() - consequences() returns an opaque > # generator object that can be drained into a list when needed; > # filter objects below are similarly opaque and drainable - define > # an auxiliary that returns a list instead if that feels scary - > # Don't Panic! > print() > print('groups of four in both lists:') > print(list(filter(isfourlong, consequences(data[0])))) > print(list(filter(isfourlong, consequences(data[1])))) > print() > print('ends of all groups in both lists:') > print(ends(consequences(data[0]))) > print(ends(consequences(data[1]))) > print() > print('ends of groups of four in both lists:') > print(ends(filter(isfourlong, consequences(data[0])))) > print(ends(filter(isfourlong, consequences(data[1])))) > print() > print('lists of ends of all groups:') > print([ends(consequences(datami)) for datami in data]) > print() > print('lists of ends of groups of four:') > print([ends(filter(isfourlong, consequences(datami))) > for datami in data]) > > if __name__ == '__main__': > # inside the above condition, these commands are executed when the > # script is executed but not when it is imported as a library, so > # it is easy to run the test from the shell and easy to import the > # definitions into an interactive session > testrun() PS: Users who did not like my suggestions above may like the alternative shown below: def compress(values): """ >>> list(compress([])) [] >>> list(compress([1])) [(1, 1)] >>> list(compress([1, 2])) [(1, 2)] >>> list(compress([1, 2, 3])) [(1, 3)] >>> list(compress([1, 2, 3, 7, 8])) [(1, 3), (7, 8)] >>> list(compress([1, 2, 3, 7, 9, 10])) [(1, 3), (7, 7), (9, 10)] >>> list(compress([3, 4, 5, 1, 2, 3, 10, 11])) [(3, 5), (1, 3), (10, 11)] >>> list(compress([1, 1])) [(1, 1), (1, 1)] >>> list(compress([1,1,2,2,3,4,7,7])) [(1, 1), (1, 2), (2, 4), (7, 7), (7, 7)] """ values = iter(values) try: first = prev = value = next(values) except StopIteration: return for value in values: if value - prev != 1: yield first, prev first = value prev = value yield first, value -- https://mail.python.org/mailman/listinfo/python-list