【问题标题】:Can list comprehensions make groups?列表推导可以分组吗?
【发布时间】:2022-04-20 05:14:10
【问题描述】:

我有一个看起来像

的列表
[(1,2,5),(2,10,13),(5,24,56),(1,8,10),(2,3,11)]

如何通过按元组的第一个元素分组并在第二个元素中找到 min 元素和在第三个元素中找到 max 元素来生成字典:

{1:(2,10),2:(3,13),5:{24,56}]

【问题讨论】:

  • 为什么这里必须是列表理解(或者更确切地说是字典理解)?尤其是当您必须同时生成最小值 最大值时,表达式会很快变得丑陋和变大。适当的循环将使代码更具可读性,并且更高效,因为您不必进行排序。

标签: python collections group-by aggregate list-comprehension


【解决方案1】:

如果您首先对分组元素排序,则可以使用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),) 循环将一个列表分配给gv,其中包含g 组中的所有元素。

简单的循环版本是:

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)}

【讨论】:

    【解决方案2】:
    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)}
    

    【讨论】:

    • 这会起作用,但会显示二次行为,因此对于长列表没有用处。
    猜你喜欢
    • 1970-01-01
    • 2021-10-15
    • 1970-01-01
    • 2015-10-14
    • 2010-11-10
    • 2016-06-14
    • 2016-04-15
    • 1970-01-01
    • 2010-09-24
    相关资源
    最近更新 更多