35

我有一个形式的结构:

>>> 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()以某种方式结束它,但是一旦任何列表变为空,它就会失败,而且还不清楚如何在不在pop()列表中查找索引的情况下使用索引。

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

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

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

[0, 1, 0, 1, 1]

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

4

9 回答 9

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

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

于 2013-06-05T17:06:51.227 回答
50

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

def argmax(iterable):
    return max(enumerate(iterable), key=lambda x: x[1])[0]
于 2014-11-04T01:14:00.397 回答
19

列表最大值的索引:

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

如果 lst 中有重复的最大值,这将返回找到的第一个最大值的索引。

于 2015-06-28T22:57:07.267 回答
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)]
于 2013-06-05T17:29:59.410 回答
4

获得 argmax 的另一种方法是:

def argmax(lst):
    return max(range(len(lst)), key=lst.__getitem__)
于 2016-09-03T21:03:01.347 回答
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]
于 2013-06-05T17:59:05.433 回答
1

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

arg_max, maximum = max(list(enumerate(nums)), key=lambda x: x[1])  # Returns both the maximum element and it's index 
于 2022-01-14T09:41:59.360 回答
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
于 2013-06-05T17:14:00.053 回答
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,这简直是陷入疯狂。

于 2013-06-06T02:09:58.430 回答