【问题标题】:minimum of list of lists列表列表的最小值
【发布时间】:2013-04-08 20:24:24
【问题描述】:

我有一个这样的列表:

[[10564, 15], [10564, 13], [10589, 18], [10637, 39], [10662, 38], [10712, 50], [10737, 15], [10762, 14], [10787, 9], [10812, 12], [10837, 45], [3, 17], [7, 21], [46, 26], [48, 12], [49, 24], [64, 14], [66,
 17], [976, 27], [981, 22], [982, 22], [983, 17], [985, 13], [517, 9], [521, 15], [525, 11], [526, 13], [528, 14], [698, 14], [788, 24], [792, 19]]

我试图找到每个列表中第二个元素的最小值(所以比较 15 到 13 到 18 等不比较 10564 和 15 ),但也将它分成范围,所以我可以说,最低的第二个元素[1] 在每个列表中,仅当元素 [0] 超过 10000 等时。我该怎么做?我试过了,目前只能比较同一列表中的元素,这不是我想要的。在我提到的情况下,我将返回 [10787, 9] 但如果有另一个超过 10000 的值 9 我也想返回它。

【问题讨论】:

    标签: python list min


    【解决方案1】:

    这取决于您想要输出什么。首先,您需要根据“范围”1

    过滤列表
    gen = (x for x in lists if x[0] > 10000)
    

    if 条件可以任意复杂(在有效语法范围内)。例如:

    gen = (x for x in lists if 5000 < x[0] < 10000)
    

    完全没问题。


    现在,如果您只想要子列表中的第二个元素:

    min(x[1] for x in gen)
    

    当然,你可以内联整个东西:

    min(x[1] for x in lists if x[0] > 10000)
    

    如果你想要整个子列表:

    from operator import itemgetter
    min(gen,key=itemgetter(1))
    

    示例:

    >>> lists = [[10564, 15], [10564, 13], [10589, 18], [10637, 39], [10662, 38], [10712, 50], [10737, 15], [10762, 14], [10787, 9], [10812, 12], [10837, 45], [3, 17], [7, 21], [46, 26], [48, 12], [49, 24], [64, 14], [66,17], [976, 27], [981, 22], [982, 22], [983, 17], [985, 13], [517, 9], [521, 15], [525, 11], [526, 13], [528, 14], [698, 14], [788, 24], [792, 19]]
    >>> gen = (x for x in lists if x[0] > 10000)
    >>> min(x[1] for x in gen)
    9
    >>> gen = (x for x in lists if x[0] > 10000)
    >>> from operator import itemgetter
    >>> min(gen,key=itemgetter(1))
    [10787, 9]
    

    不幸的是,这些只会为您提供与条件匹配的 first 子列表。要获得所有这些:

    target = min(x[1] for x in lists if x[0] > 10000)
    matches = [x for x in lists if (x[1] == target) and (x[0] > 10000)]
    

    如果您确定匹配的次数少于N,则可以使用heapqitertools.takewhile 更有效地执行此操作。在您不知道匹配数上限的一般情况下,我认为这种解决方案更好(与 O(NlogN) 的排序相比,它是 O(N))。


    1注意“生成器表达式”在用完之前只能迭代一次

    【讨论】:

    • 很好的答案。是的,我想返回 [10787, 9] 我将阅读 itemgetter。我不理解您所说的生成器表达式已用尽的意思。由于某种原因我不能再次迭代它?
    • @Paul -- 没错。生成器只能迭代一次。通常这不是问题(您总是可以创建另一个)。但是,如果有问题,您可以改用列表推导:lst = [x for x in lists if x[0] &gt; 10000]
    • 啊,我明白了,完美。谢谢。更熟悉列表推导。除了括号外,我看不出任何区别,我必须阅读与生成器的区别,谢谢。
    • @Paul -- 在语法方面,唯一的区别是括号。就功能而言,生成器动态生成数字序列,yield仅在被询问时(例如通过 for 循环)。您可以将列表理解视为迭代生成器并将每个值存储到列表中的结构。因此,这里的一个区别在于存储/内存使用情况。
    • "但是如果有另一个值超过 10000 和 9,我也想返回它。" - 这个案子呢?
    【解决方案2】:
    >>> l=[[10564, 15], [10564, 13], [10589, 18], [10637, 39]]
    >>> min(x[1] for x in l if x[0] > 10000)
    13
    >>>
    

    更新您的评论(您可以在 min 函数中使用 lambda,在大型列表中使用 itemgetter 更快):

    >>> min((x for x in l if x[0] > 10000), key=lambda k:k[1])
    [10564, 13]
    

    【讨论】:

    • 谢谢,很简单,在这种情况下我想返回 [10564, 13]。
    • 这将是我最喜欢的,除了如果没有x[0]&gt;10000 持有,你会得到ValueError: min() arg is an empty sequence。所以你需要把它包装在一个 try: - except 块中,除非你能找到一种方法来潜入 min 的哨兵值(我认为这并不容易)
    • @Paul 为了使这段代码更加自文档化,考虑解压缩x[0]x[1] 并给它们起描述性的名称,就像这样,我只是在猜测x[0] 和@987654330 是什么@ 可能是:min(id for score, id in l if score &gt; 10000).
    • @LauritzV.Thaulow 是的,一个更具描述性的变量名称总是更可取!就算是我自己,更别说别人了。
    【解决方案3】:

    这是一种非常简单的方法,只需找到最小值,然后根据该值构建列表。

    >>> a = [[10564, 15], [10564, 13], [10589, 18], [10637, 39], [10662, 38], [10712, 50], [10737, 15], [10762, 14], [10787, 9], [10812, 12], [10837, 45], [3, 17], [7, 21], [46, 26], [48, 12], [49, 24], [64, 14], [66,
    ...  17], [976, 27], [981, 22], [982, 22], [983, 17], [985, 13], [517, 9], [521, 15], [525, 11], [526, 13], [528, 14], [698, 14], [788, 24], [792, 19]]
    >>> a_min = min(i[1] for i in a)
    >>> [i[0] for i in a if i[1] == a_min and i[0] > 10000] + [a_min]
    [10787, 9]
    

    代码正确显示多个值:

    >>> a += [[10391, 9]] #add another pair with a first value > 10000
    >>> [i[0] for i in a if i[1] == a_min and i[0] > 10000] + [a_min]
    [10787, 10391, 9]
    

    【讨论】:

    • 非常好,我喜欢所有可能相等值的小列表!
    • 我想我宁愿写a.append(lst)而不是a += [lst]
    • 另外,为什么:[i[0] for i in a if i[1] == a_min and i[0] &gt; 10000] + [a_min] 而不是:[i for i in a if i[1] == a_min and i[0] &gt; 10000]
    【解决方案4】:

    如果您需要多个mins,那么也许您最好过滤适用的元素并对其进行排序...

    vals = sorted((el for el in your_list if el[0] >= 10000), key=lambda L: L[1])
    # [[10787, 9], [10812, 12], [10564, 13], [10762, 14], [10564, 15], [10737, 15], [10589, 18], [10662, 38], [10637, 39], [10837, 45], [10712, 50]]
    

    那你可以用vals[0]取第一个,vals[1]取第二个,或者用vals[:5]等切片...

    【讨论】:

    • 这里你甚至可以使用itertools.takewhile 拉取L where L[1] == vals[0][1]
    【解决方案5】:
    a=[[10564, 15], [10564, 13], [10589, 18], [10637, 39], [10662, 38], [10712, 50], [10737, 15], [10762, 14], [10787, 9], [10812, 12], [10837, 45], [3, 17], [7, 21], [46, 26], [48, 12], [49, 24], [64, 14], [66, 17], [976, 27], [981, 22], [982, 22], [983, 17], [985, 13], [517, 9], [521, 15], [525, 11], [526, 13], [528, 14], [698, 14], [788, 24], [792, 19]]
    
    print min(map(lambda y: y[1] ,filter(lambda x: x[0]>10000,a)))
    

    【讨论】:

    • 谢谢,我也会试一试以了解它。
    猜你喜欢
    • 2016-09-04
    • 1970-01-01
    • 2021-07-28
    • 2016-04-14
    • 2022-01-25
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多