繁体   English   中英

查找 Python 中最小值或最大值的索引

[英]Finding the index of the value which is the min or max in Python

我有一个形式的结构:

>>> items
[([[0, 1], [2, 20]], 'zz', ''), ([[1, 3], [5, 29], [50, 500]], 'a', 'b')]

每个元组中的第一项是范围列表,我想制作一个生成器,根据起始索引按升序为我提供范围。

由于范围列表已经按其起始索引排序,因此此操作很简单:它只是一个排序合并。 我希望以良好的计算效率来做到这一点,所以我认为隐式跟踪我的合并的 state 的一种好方法是简单地弹出元组列表的前面,该元组的起始索引在其范围列表。

我可以使用min()来获得[0, 1]这是我想要的第一个,但我如何获得它的索引?

我有这个:

[ min (items[i][0]) for i in range(len(items)) ]

这给了我每个列表中的第一个项目,然后我可以min()以某种方式进行,但是一旦任何列表变空它就会失败,而且还不清楚如何让索引在不看的情况下使用pop()备份在列表中。

总结一下:想要构建为我返回的生成器:

([0,1], 'zz', '')
([1,3], 'a', 'b')
([2,20], 'zz', '')
([5,29], 'a', 'b')
([50,500], 'a', 'b')

或者更有效地,我只需要这些数据:

[0, 1, 0, 1, 1]

(我想取前面的元组的索引)

 from operator import itemgetter
 index, element = max(enumerate(items), key=itemgetter(1))

返回items最大元素的索引和元素本身。

此方法查找任何可迭代的最大元素的索引,并且不需要任何外部导入:

def argmax(iterable):
    return max(enumerate(iterable), key=lambda x: x[1])[0]

列表最大值的索引:

def argmax(lst):
  return lst.index(max(lst))

如果lst中存在重复的最大值,则返回找到的第一个最大值的索引。

这有效:

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

得到:

[0, 1, 0, 1, 1]

详细。 发电机:

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

因此,唯一需要的是排序并获得所需的索引:

[item[1] for item in sorted(by_index)]

获得argmax的另一种方法是:

def argmax(lst):
    return max(range(len(lst)), key=lst.__getitem__)

所以这是一个真正快速简便的方法来获得您正在寻找的高效版本:

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

这是与您的项目,以显示它的工作原理:

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

如果您不尝试使用内部范围列表进行排序的事实,这很容易

sorted(sum([ [(rng,) + i[1:] for rng in i[0]] for i in items ], []), lambda i: i[0][0])

听起来你想要一个返回最小值索引的函数

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

我不确定发生了什么,但我认为每个人都有点不合时宜。 我会把它归咎于做一个糟糕的工作来解释我正试图解决的问题。 无论如何,这是我得到了多少:

items[min(range(len(items)), key = lambda x: items[x][0][0])][0].pop(0)

这让我大部分都在那里,但剩下要处理的是处理一个列表已经用尽的情况。 一旦处理好它应该是微不足道的,使它成为一个生成器,因为我可以把它放在一个循环中并在其中产生,并且也希望没有太多的工作,这可以适应于执行有效的排序合并生成器。

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

更新:

将剩余有效物品的适当子集组装成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                                           

执行:

$ 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)
[]

我会注意到这仍然可以改进,每次迭代都会重建idxs列表。 它不需要,但这样做并没有改善渐近界限...当然,人们不得不怀疑我们是否真的关心性能,是否使用lambda也是一个好主意,尽管我真的不这样做看看周围的方式,而不分开min ,这只是疯狂的下降。

最简单最有效的方式(O(n))

arg_max, maximum = max(list(enumerate(nums)), key=lambda x: x[1])  # Returns both the maximum element and it's index 

另一种选择:

max(zip(lst, range(len(lst))))[0]

这似乎是最快的,连同

max(range(len(lst)), key=lst.__getitem__)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM