如何根据嵌套列表中内部列表的第一个元素获取所有最小元素?

时间:2010-08-21 09:55:09

标签: python list minimum

简单地说!有这个列表说LST = [[12,1],[23,2],[16,3],[12,4],[14,5]],我希望根据内部列表的第一个元素获取此列表的所有最小元素。因此,对于上面的示例,答案为[12,1][12,4]。这样做python中有什么典型的方法吗? 提前感谢你。

4 个答案:

答案 0 :(得分:5)

两遍:

minval = min(LST)[0]
return [x for x in LST if x[0] == minval]

一遍:

def all_minima(iterable, key=None):
  if key is None: key = id
  hasminvalue = False
  minvalue = None
  minlist = []
  for entry in iterable:
     value = key(entry)
     if not hasminvalue or value < minvalue:
        minvalue = value
        hasminvalue = True
        minlist = [entry]
     elif value == minvalue:
        minlist.append(entry)
  return minlist

from operator import itemgetter
return all_minima(LST, key=itemgetter(0))

答案 1 :(得分:3)

紧凑的单通道解决方案需要对列表进行排序 - 技术上O(N log N)用于N长列表,但Python的排序非常好,而且很多序列“只是发生”才有它们中的一些嵌入式顺序(timsort巧妙地利用它来加快速度),基于排序的解决方案有时在现实世界中具有令人惊讶的良好性能。

这是一个需要2.6或更高的解决方案:

import itertools
import operator
f = operator.itemgetter(0)

def minima(lol):
  return list(next(itertools.groupby(sorted(lol, key=f), key=f))[1])

要理解这种方法,“从内向外看”会有所帮助。

f,即operator.itemgetter(0),是一个关键函数,它为了排序目的选择其参数的第一项 - operator.itemgetter的目的是轻松紧凑地构建这样的功能。

因此,

sorted(lol, key=f)会返回列表列表lol的已排序副本,通过增加第一项来排序。如果省略key=f,将按字典顺序排序已排序的副本,因此它按顺序增加第一项,但仅作为“主键” - 项目与相同的第一个子项将依次通过其第二个子项的值进行排序,依此类推 - 当 key=f时,您可以保证保留具有相同第一子项目的项目之间的原始顺序。你没有指定你需要的行为(在你的例子中,这两个行为碰巧产生相同的结果,所以我们无法区分那个例子)这就是为什么我仔细详细说明这两种可能性,以便你可以选择。

itertools.groupby(sorted(lol, key=f), key=f)执行作为操作核心的“分组”任务:它从序列中生成 groups (在这种情况下,序列sorted提供)在key订购标准上。也就是说,当您使用项目作为参数调用f时,所有相邻项目之间产生相同值的组,然后具有所有相邻项目的组产生与第一组不同的值(但它们之间相同) ),等等。 groupby尊重序列作为参数的顺序,这就是为什么我们必须首先对lol进行排序(groupby的这种行为使得它在许多情况下非常有用序列的排序很重要。)

yield的每个结果groupby都是一对k, g:一个键k,它是组中每个项目f(i)的结果,迭代器g按顺序生成组中的每个项目。

给定迭代器的next内置(此解决方案中唯一需要Python 2.6的位)产生下一个项目 - 特别是在新创建的迭代器上调用时的第一个项目(和,当然的每个生成器都是迭代器,groupby的结果也是如此)。在早期的Python版本中,它必须是groupby(...).next()(因为next只是一个迭代器的方法,而不是内置的),从2.6开始就不推荐使用。

总而言之,我们的next(...)的结果恰好是k, g对,其中k是第一个子项的最小值(即排序后的第一个),并且g是该组项目的迭代器。

所以,使用[1]我们只选择迭代器,所以我们有一个迭代器,只产生我们想要的子项。

由于我们需要一个列表,而不是一个迭代器(根据您的规范),最外面的list(...)调用完成了这项工作。

所有这些都值得,表现明智吗?不是你提供的小例子列表 - minima实际上比@ Kenny的答案中的任何一个代码慢(其中第一个,“两遍”解决方案更快)。我认为值得记住的是你可能遇到的下一个序列处理问题,其中典型输入的细节可能完全不同(更长的列表,更罕见的最小值,输入中的部分排序, &amp; c,&amp; c; - )。

答案 2 :(得分:2)

m = min(LST, key=operator.itemgetter(0))[0]
print [x for x in LST if x[0] == m]

答案 3 :(得分:-1)

minval = min(x[0] for x in LST)
result = [x for x in LST if x[0]==minval]