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

发布于 2024-09-15 13:39:25 字数 191 浏览 9 评论 0原文

简单地说!有这个列表说 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

疯了 2024-09-22 13:39:25

两次通过:

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

Two passes:

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

One pass:

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))
属性 2024-09-22 13:39:25

紧凑的单遍解决方案需要对列表进行排序——从技术上来说,对于 N 长列表来说,这是 O(N log 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,排序后的副本将按字典顺序排序,因此它也将按第一项递增的顺序排列,但这仅充当“主键” " -- 具有相同第一个子项目的项目将按照第二个子项目的值依次在它们之间排序,依此类推 -- 而 with key=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 an N-long list, but Python's sort is so good, and so many sequences "just happen" to have some embedded order in them (which timsort 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:

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

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

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 of operator.itemgetter is to easily and compactly build such functions.

sorted(lol, key=f) therefore returns a sorted copy of the list-of-lists lol, ordered by increasing first item. If you omit the key=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 the key=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 sequence sorted provides) based on the key ordering criteria. That is, a group with all adjacent items producing the same value among themselves when you call f 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 the lol first (and this behavior of groupby makes it very useful in many cases in which the sequence's ordering does matter).

Each result yielded by groupby is a pair k, g: a key k which is the result of f(i) on each item in the group, an iterator g 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 is groupby's result). In earlier Python versions, it would have to be groupby(...).next() (since next 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 pair k, g where k is the minimum (i.e., first after sorting) value for the first sub-item, and g 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;-).

開玄 2024-09-22 13:39:25
m = min(LST, key=operator.itemgetter(0))[0]
print [x for x in LST if x[0] == m]
m = min(LST, key=operator.itemgetter(0))[0]
print [x for x in LST if x[0] == m]
谜兔 2024-09-22 13:39:25
minval = min(x[0] for x in LST)
result = [x for x in LST if x[0]==minval]
minval = min(x[0] for x in LST)
result = [x for x in LST if x[0]==minval]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文