查找值的索引,即 Python 中的最小值或最大值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16945518/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Finding the index of the value which is the min or max in Python
提问by Steven Lu
I've got a structure of the form:
我有一个形式的结构:
>>> items
[([[0, 1], [2, 20]], 'zz', ''), ([[1, 3], [5, 29], [50, 500]], 'a', 'b')]
The first item in each tuple is a list of ranges, and I want to make a generator that provides me the ranges in ascending order based on the starting index.
每个元组中的第一项是范围列表,我想制作一个生成器,根据起始索引按升序为我提供范围。
Since the range-lists are already sorted by their starting index this operation is simple: it is just a sorted merge. I'm hoping to do it with good computational efficiency, so I'm thinking that one good way to implicitly track the state of my merge is to simply pop the front off of the list of the tuple which has the smallest starting index in its range list.
由于范围列表已经按它们的起始索引排序,这个操作很简单:它只是一个排序的合并。我希望以良好的计算效率来完成它,所以我认为隐式跟踪我的合并状态的一种好方法是简单地从具有最小起始索引的元组列表中弹出前面范围列表。
I can use min()to obtain [0, 1]which is the first one I want, but how do I get the index of it?
我可以用它min()来获取[0, 1]我想要的第一个,但我如何获得它的索引?
I have this:
我有这个:
[ min (items[i][0]) for i in range(len(items)) ]
which gives me the first item in each list, which I can then min()over somehow, but it fails once any of the lists becomes empty, and also it's not clear how to get the index to use pop()with without looking it back up in the list.
这给了我每个列表中的第一项,然后我可以min()以某种方式结束它,但是一旦任何列表变空它就会失败,而且也不清楚如何在不在pop()列表中查找它的情况下使用索引。
To summarize: Want to build generator that returns for me:
总结一下:想要构建为我返回的生成器:
([0,1], 'zz', '')
([1,3], 'a', 'b')
([2,20], 'zz', '')
([5,29], 'a', 'b')
([50,500], 'a', 'b')
Or even more efficiently, I only need this data:
或者更有效的是,我只需要这些数据:
[0, 1, 0, 1, 1]
(the indices of the tuples i want to take the front item of)
(我想取前项的元组的索引)
采纳答案by Mike Müller
This works:
这有效:
by_index = ([sub_index, list_index] for list_index, list_item in
enumerate(items) for sub_index in list_item[0])
[item[1] for item in sorted(by_index)]
Gives:
给出:
[0, 1, 0, 1, 1]
In detail. The generator:
详细。发电机:
by_index = ([sub_index, list_index] for list_index, list_item in
enumerate(items) for sub_index in list_item[0])
list(by_index)
[[[0, 1], 0], [[2, 20], 0], [[1, 3], 1], [[5, 29], 1], [[50, 500], 1]]
So the only thing needed is sorting and getting only the desired index:
所以唯一需要的是排序并只获取所需的索引:
[item[1] for item in sorted(by_index)]
回答by MatthieuBizien
from operator import itemgetter
index, element = max(enumerate(items), key=itemgetter(1))
Return the index of the biggest element in itemsand the element itself.
返回最大元素的索引items和元素本身。
回答by Phil Reinhold
It's easy if you don't try to use the fact that the internal range lists are sorted
如果您不尝试使用内部范围列表已排序的事实,这很容易
sorted(sum([ [(rng,) + i[1:] for rng in i[0]] for i in items ], []), lambda i: i[0][0])
It sounds like you want a function that returns the index of the smallest value though
听起来你想要一个返回最小值索引的函数
def min_idx(l, key=lambda x: x):
min_i, min_key = None, float('inf')
for i, v in enumerate(l):
key_v = key(v)
if key_v < min_key:
mini_i = i
min_key = key_v
return min_i
def merge_items(items):
res = []
while True:
i = min_idx(items, key=lambda i: i[0][0][0])
item = items[i]
res.append((item[0][0],) + item[1:])
return res
回答by Ryan Saxe
so this is a real quick and easy way to get that efficient version you are looking for:
所以这是获得您正在寻找的高效版本的真正快速简便的方法:
a = []
count = 0
for i in items:
for x in i[0]:
#place a list with the index next to it in list a for sorting
a.append((x,count))
#continually grabs the smallest list and returns the index it was in
sort = [a.pop(a.index(min(a)))[1] for i in range(len(a))]
Here is it with your items to show that it works:
这是您的物品以表明它有效:
>>> items = [([[0, 1], [2, 20]], 'zz', ''), ([[1, 3], [5, 29], [50, 500]], 'a', 'b')]
>>> a = []
>>> count = 0
>>> for i in items:
... for x in i[0]:
... a.append((x,count))
... count += 1
...
>>> sort = [a.pop(a.index(min(a)))[1] for i in range(len(a))]
>>> sort
[0, 1, 0, 1, 1]
回答by Steven Lu
I'm not sure what happened but I think everyone's a bit off the mark. I'll blame it on doing a bad job explaining the problem I'm trying to solve. Anyway, here's how much I've gotten:
我不确定发生了什么,但我认为每个人都有些离题。我会把它归咎于解释我试图解决的问题时做得不好。无论如何,这是我得到了多少:
items[min(range(len(items)), key = lambda x: items[x][0][0])][0].pop(0)
This takes me most of the way there but what's left to deal with is treating the situation where one list has been exhausted. Once that's taken care of it should be trivial to make this a generator as I can just put it in a loop and yield inside it, and also hopefully without too much more work this can be adapted into performing an efficient sort-merge over generators.
这花了我大部分时间,但剩下要处理的是处理一个列表已经用尽的情况。一旦解决了这个问题,让它成为一个生成器应该是微不足道的,因为我可以把它放在一个循环中并在它里面产生,而且希望没有太多的工作,这可以适应对生成器执行有效的排序合并。
>>> items[min(range(len(items)), key = lambda x: items[x][0][0])][0].pop(0)
[0, 1]
>>> items[min(range(len(items)), key = lambda x: items[x][0][0])][0].pop(0)
[1, 3]
>>> items[min(range(len(items)), key = lambda x: items[x][0][0])][0].pop(0)
[2, 20]
>>> items[min(range(len(items)), key = lambda x: items[x][0][0])][0].pop(0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
IndexError: list index out of range
Update:
更新:
Assembling the proper subset of still-valid-items to minover is the ticket.
将仍然有效的项目的正确子集组装到上面min是票。
def next_value_in_sections(sections):
while 1:
idxs = []
for i, x in enumerate(sections):
if x[0]:
idxs.append(i)
print idxs
if not idxs:
break
j = min(idxs, key=lambda x: sections[x][0][0])
yield (sections[j][0].pop(0), j)
items = [([[0, 1], [2, 20]], 'zz', ''),
([[1, 3], [5, 29], [50, 500]], 'a', 'b')]
x = next_value_in_sections(items)
for i in x:
print i
Executed:
执行:
$ python test.py
[0, 1]
([0, 1], 0)
[0, 1]
([1, 3], 1)
[0, 1]
([2, 20], 0)
[1]
([5, 29], 1)
[1]
([50, 500], 1)
[]
I'll note this still can be improved, the idxs list is being rebuilt each iteration. It does not need to be, but doing that does not improve asymptotic bound... Of course, one has to wonder if we really care about performance, whether the use of the lambda is a good idea either, though I really don't see a way around that without taking apart min, which is simply a descent into madness.
我会注意到这仍然可以改进,每次迭代都会重建 idxs 列表。它不一定是,但这样做并不能改善渐近界......当然,人们不得不怀疑我们是否真的关心性能,使用 lambda 是否也是一个好主意,尽管我真的不在不拆开的情况下找到解决方法min,这简直是陷入疯狂。
回答by 1''
This method finds the index of the maximum element of any iterable and does not require any external imports:
此方法查找任何可迭代的最大元素的索引,并且不需要任何外部导入:
def argmax(iterable):
return max(enumerate(iterable), key=lambda x: x[1])[0]
回答by stupidsven
The index of the max of a list:
列表最大值的索引:
def argmax(lst):
return lst.index(max(lst))
If there are duplicate max values in lst, this will return the index of the first maximum value found.
如果 lst 中有重复的最大值,这将返回找到的第一个最大值的索引。
回答by yoniLavi
Yet another way to get the argmax is:
另一种获取 argmax 的方法是:
def argmax(lst):
return max(range(len(lst)), key=lst.__getitem__)

