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