问题
Consider the following simplified case:
lol = [['John','Polak',5,3,7,9],
['John','Polak',7,9,2,3],
['Mark','Eden' ,0,3,3,1],
['Mark','Eden' ,5,1,2,9]]
What would be a pythonic and memory+speed efficient way to transform this list-of-lists to a list-of-lists-of-lists based on the first two parameters:
lolol = [[['John','Polak',5,3,7,9],
['John','Polak',7,9,2,3]],
[['Mark','Eden' ,0,3,3,1],
['Mark','Eden' ,5,1,2,9]]]
Actually - any other data structure would also be ok, as long as I have the correct hierarchy. For example the following dictionary structure comes to mind, but creating it doesn't seem efficient speed-efficient enough, and the memory would probably be higher than the lolol solution.
dolol = {('John','Polak'):[[5,3,7,9],[7,9,2,3]],
('Mark','Eden') :[[0,3,3,1],[5,1,2,9]]}
回答1:
List:
from itertools import groupby
lolol = [list(grp) for (match, grp) in groupby(lol, lambda lst: lst[:2])]
# [[['John', 'Polak', 5, 3, 7, 9], ['John', 'Polak', 7, 9, 2, 3]],
# [['Mark', 'Eden', 0, 3, 3, 1], ['Mark', 'Eden', 5, 1, 2, 9]]]
Dictionary:
dolol = dict((tuple(match), [x[2:] for x in grp]) for (match, grp) in
groupby(lol, lambda lst: lst[:2]))
# {('John', 'Polak'): [[5, 3, 7, 9], [7, 9, 2, 3]],
# ('Mark', 'Eden'): [[0, 3, 3, 1], [5, 1, 2, 9]]}
Since itertools.groupby
works on consecutive matches, it assumes sorted input (lol
).
回答2:
If a dictionary is acceptable, this code will create one:
import collections
d = collections.defaultdict(list)
for name, surname, *stuff in lol:
d[name, surname].append(nums)
Note that this requires Python 3 (extended iterable unpacking). For Python 2, use
for x in lol:
name = x[0]
surname = x[1]
stuff = x[2:]
You may fold the variables to save lines.
回答3:
To complement delnan's answer with a Python 2 equivalent:
from collections import defaultdict
dolol=defaultdict(list)
for data in lol:
dolol[data[0],data[1]].append(data[2:])
来源:https://stackoverflow.com/questions/4980414/python-dividing-a-list-of-lists-to-groups