在Python中查找值为min或max的索引

时间:2013-06-05 16:46:55

标签: python

我有一个结构形式:

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

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

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

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

我有这个:

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

它给了我每个列表中的第一个项目,然后我可以min()以某种方式,但是一旦任何列表变为空,它就会失败,并且还不清楚如何使索引使用{{ 1}}没有在列表中查找它。

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

pop()

甚至更有效率,我只需要这些数据:

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

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

8 个答案:

答案 0 :(得分:45)

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

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

答案 1 :(得分:30)

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

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

答案 2 :(得分:11)

列表最大值的索引:

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

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

答案 3 :(得分:4)

这有效:

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

答案 4 :(得分:2)

获得argmax的另一种方法是:

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

答案 5 :(得分:1)

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

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]

答案 6 :(得分:0)

如果您不尝试使用内部范围列表已排序的事实

,这很容易
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

答案 7 :(得分:0)

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

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的情况下看到一种解决方法,这只是疯狂的下降。