如何根据嵌套列表中内部列表的第一个元素获取所有最小元素?
简单地说!有这个列表说 LST = [[12,1],[23,2],[16,3],[12,4],[14,5]]
我想得到该列表的所有最小元素根据其内部列表的第一个元素。因此,对于上面的示例,答案将是 [12,1]
和 [12,4]
。 python中有没有典型的方法来做到这一点? 预先感谢您。
Simply put! there is this list say LST = [[12,1],[23,2],[16,3],[12,4],[14,5]]
and i want to get all the minimum elements of this list according to its first element of the inside list. So for the above example the answer would be [12,1]
and [12,4]
. Is there any typical way in python of doing this?
Thanking you in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
两次通过:
一次通过:
Two passes:
One pass:
紧凑的单遍解决方案需要对列表进行排序——从技术上来说,对于
N
长列表来说,这是O(N log N)
,但 Python 的排序非常好,所以许多序列“恰好”有一些嵌入的顺序(timsort 巧妙地利用它来加快速度),基于排序的解决方案有时在现实世界中具有令人惊讶的良好性能。这是一个需要 2.6 或更高版本的解决方案:
要理解这种方法,“从内到外”查看会有所帮助。
f
,即operator.itemgetter(0)
,是一个关键函数,它选择其参数的第一项以进行排序——这正是的目的operator.itemgetter
就是为了轻松、紧凑地构建此类函数。因此,
sorted(lol, key=f)
返回列表列表lol
的排序副本,按增加第一项进行排序。如果省略key=f
,排序后的副本将按字典顺序排序,因此它也将按第一项递增的顺序排列,但这仅充当“主键” " -- 具有相同第一个子项目的项目将按照第二个子项目的值依次在它们之间排序,依此类推 -- 而 withkey=f< /code> 您保证保留具有相同第一个子项目的项目之间的原始顺序。您没有指定您需要哪种行为(并且在您的示例中,这两种行为恰好产生相同的结果,因此我们无法与该示例区分开),这就是为什么我仔细详细说明这两种可能性,以便您可以选择。
itertools.groupby(sorted(lol, key=f), key=f)
执行作为操作核心的“分组”任务:它从基于key
排序标准的序列(在本例中为sorted
提供的序列)。也就是说,当您使用该项目作为参数调用f
时,所有相邻项目的组都会产生相同的值,然后所有相邻项目的组都会产生与第一组不同的值(但是彼此之间相同),等等。groupby
尊重它作为参数的序列的顺序,这就是为什么我们必须首先对lol
进行排序(以及groupby
的这种行为)使得它在许多情况下非常有用,其中序列的顺序确实很重要)。groupby
生成的每个结果都是一对k, g
:一个键k
,它是k
的结果code>f(i) 在组中的每个项目上,迭代器g
按顺序生成组中的每个项目。给定迭代器的
next
内置函数(此解决方案中唯一需要 Python 2.6 的位)会生成下一个项目 - 特别是在新创建的迭代器上调用时的第一个项目(并且,当然每个生成器都是一个迭代器,groupby
的结果也是如此。在早期的 Python 版本中,它必须是groupby(...).next()
(因为next
只是迭代器的一个方法,而不是内置方法) ,自 2.6 起已弃用。因此,总而言之,我们的
next(...)
的结果正是k, g
对,其中k
是最小值(即,排序后的第一个)第一个子项目的值,g
是该组项目的迭代器。因此,通过
[1]
我们只选择迭代器,这样我们就有了一个只生成我们想要的子项的迭代器。由于我们需要一个列表,而不是一个迭代器(根据您的规范),最外面的
list(...)
调用完成了这项工作。从性能角度来看,这一切值得吗?不在您给出的小示例列表中 -
minima
实际上比 @Kenny 的答案中的任何代码都慢(其中第一个“两次传递”解决方案速度更快)。我只是认为值得牢记您可能遇到的下一个序列处理问题的想法,其中典型输入的细节可能完全不同(更长的列表,更罕见的最小值,输入中的部分排序, &c,&c;-)。A compact single-pass solution requires sorting the list -- that's technically
O(N log N)
for anN
-long list, but Python's sort is so good, and so many sequences "just happen" to have some embedded order in them (whichtimsort
cleverly exploits to go faster), that sorting-based solutions sometimes have surprisingly good performance in the real world.Here's a solution requiring 2.6 or better:
To understand this approach, looking "from the inside, outwards" helps.
f
, i.e.,operator.itemgetter(0)
, is a key-function that picks the first item of its argument for ordering purposes -- the very purpose ofoperator.itemgetter
is to easily and compactly build such functions.sorted(lol, key=f)
therefore returns a sorted copy of the list-of-listslol
, ordered by increasing first item. If you omit thekey=f
the sorted copy will be ordered lexicographically, so it will also be in order of increasing first item, but that acts only as the "primary key" -- items with the same first sub-item will in turn be sorted among them by the values of their second sub-items, and so forth -- while with thekey=f
you're guaranteed to preserve the original order among items with the same first sub-item. You don't specify which behavior you require (and in your example the two behaviors happen to produce the same result, so we cannot distinguish from that example) which is why I'm carefully detailing both possibilities so you can choose.itertools.groupby(sorted(lol, key=f), key=f)
performs the "grouping" task that is the heart of the operation: it yields groups from the sequence (in this case, the sequencesorted
provides) based on thekey
ordering criteria. That is, a group with all adjacent items producing the same value among themselves when you callf
with the item as an argument, then a group with all adjacent item producing a different value from the first group (but same among themselves), and so forth.groupby
respect the ordering of the sequence it takes as its argument, which is why we had to sort thelol
first (and this behavior ofgroupby
makes it very useful in many cases in which the sequence's ordering does matter).Each result
yield
ed bygroupby
is a pairk, g
: a keyk
which is the result off(i)
on each item in the group, an iteratorg
which yields each item in the group in sequence.The
next
built-in (the only bit in this solution which requires Python 2.6) given an iterator produces its next item -- in particular, the first item when called on a fresh, newly made iterator (and, every generator of course is an iterator, as isgroupby
's result). In earlier Python versions, it would have to begroupby(...).next()
(sincenext
was only a method of iterators, not a built-in), which is deprecated since 2.6.So, summarizing, the result of our
next(...)
is exactly the pairk, g
wherek
is the minimum (i.e., first after sorting) value for the first sub-item, andg
is an iterator for the group's items.So, with that
[1]
we pick just the iterator, so we have an iterator yielding just the subitems we want.Since we want a list, not an iterator (per your specs), the outermost
list(...)
call completes the job.Is all of this worth it, performance-wise? Not on the tiny example list you give --
minima
is actually slower than either code in @Kenny's answer (of which the first, "two-pass" solution is speedier). I just think it's worth keeping the ideas in mind for the next sequence processing problem you may encounter, where the details of typical inputs may be quite different (longer lists, rarer minima, partial ordering in the input, &c, &c;-).