How to store some elements from a list into another
Peter Otten
__peter__ at web.de
Tue Jun 13 06:00:30 EDT 2017
Jussi Piitulainen wrote:
> breamoreboy at 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
More information about the Python-list
mailing list