列表推导可以分组吗?
我有一个列表,长得像这样:
[(1,2,5),(2,10,13),(5,24,56),(1,8,10),(2,3,11)]
我想通过把元组的第一个元素分组,来生成一个字典,并且在第二个元素中找到最小值,在第三个元素中找到最大值:
{1:(2,10),2:(3,13),5:{24,56}]
2 个回答
0
In [9]: ll = [(1,2,5),(2,10,13),(5,24,56),(1,8,10),(2,3,11)]
In [10]: {k[0]: ( min([kk[1] for kk in ll if kk[0] == k[0]]), max([kk[2] for kk in ll if kk[0] == k[0]]) ) for k in ll}
Out[10]: {1: (2, 10), 2: (3, 13), 5: (24, 56)}
或者
In [11]: {k[0]: (v[0], v[-1]) for k in ll for v in [sorted([x for y in [[kk[1], kk[2]] for kk in ll if kk[0] == k[0] ] for x in y])] }
Out[11]: {1: (2, 10), 2: (3, 13), 5: (24, 56)}
6
你可以先对分组的元素进行排序,然后使用itertools.groupby()
来对这些元素进行分组,并测试每组的最小值和最大值。因为这些组是生成器,所以你需要多做一步,把它们转换成一个可以重复使用的列表,以便使用min()
和max()
函数:
from itertools import groupby
from operator import itemgetter
result = {k: (min(item[1] for item in gv), max(item[2] for item in gv))
for k, g in groupby(sorted(inputlist, key=itemgetter(0)), itemgetter(0))
for gv in (list(g),)}
需要注意的是,这个过程先是排序(复杂度是O(NlogN)),然后对每个组循环两次,以找到每组的最小值和最大值,这样总的复杂度又增加了2N。
额外的for gv in (list(g),)
循环是把g
组中的所有元素放到一个列表中,赋值给gv
。
简单的循环版本是:
result = {}
for key, v1, v2 in inputlist:
minimum, maximum = result.get(key, (float('inf'), float('-inf')))
if v1 < minimum:
minimum = v1
if v2 > maximum:
maximum = v2
result[key] = (minimum, maximum)
这是一个简单的O(N)循环,而且更容易理解。
这两种方法的演示:
>>> from itertools import groupby
>>> from operator import itemgetter
>>> inputlist = [(1,2,5),(2,10,13),(5,24,56),(1,8,10),(2,3,11)]
>>> {k: (min(item[1] for item in gv), max(item[2] for item in gv))
... for k, g in groupby(sorted(inputlist, key=itemgetter(0)), itemgetter(0))
... for gv in (list(g),)}
{1: (2, 10), 2: (3, 13), 5: (24, 56)}
还有
>>> result = {}
>>> for key, v1, v2 in inputlist:
... minimum, maximum = result.get(key, (float('inf'), float('-inf')))
... if v1 < minimum:
... minimum = v1
... if v2 > maximum:
... maximum = v2
... result[key] = (minimum, maximum)
...
>>> result
{1: (2, 10), 2: (3, 13), 5: (24, 56)}