it-swarm.com.de

Ermitteln des Index des Werts, der in Python in min oder max liegt

Ich habe eine Struktur des Formulars:

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

Das erste Element in jedem Tuple ist eine Liste von Bereichen, und ich möchte einen Generator erstellen, der mir die Bereiche in aufsteigender Reihenfolge basierend auf dem Startindex liefert. 

Da die Bereichslisten bereits nach ihrem Startindex sortiert sind, ist diese Operation einfach: Es handelt sich lediglich um eine sortierte Zusammenführung. Ich hoffe, dies mit einer guten Rechenleistung zu erreichen, daher denke ich, dass ein guter Weg, den Status meiner Zusammenführung implizit zu verfolgen, darin besteht, einfach die Liste der Tupel zu platzieren, die den kleinsten Startindex in ihrem Verzeichnis haben Bereichsliste. 

Ich kann min() verwenden, um [0, 1] zu erhalten, den ersten, den ich möchte, aber wie erhalte ich den Index davon? 

Ich habe das: 

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

das gibt mir den ersten Eintrag in jeder Liste, den ich dann min() irgendwie übergehen kann, aber es schlägt fehl, sobald eine der Listen leer wird, und es ist auch nicht klar, wie der Index pop() mit verwendet werden kann, ohne dass er in der Liste nachgeschlagen wird Liste. 

Zusammenfassend: Ich möchte einen Generator bauen, der für mich zurückkehrt: 

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

Oder noch effizienter, ich brauche nur diese Daten: 

[0, 1, 0, 1, 1]

(die Indizes der Tupel, von denen ich den vorderen Punkt nehmen möchte)

17
Steven Lu

Das funktioniert:

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

Gibt:

[0, 1, 0, 1, 1]

Im Detail. Der 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]]

Das einzige, was nötig ist, ist das Sortieren und Erhalten des gewünschten Indexes:

[item[1] for item in sorted(by_index)]
3
Mike Müller
 from operator import itemgetter
 index, element = max(enumerate(items), key=itemgetter(1))

Gibt den Index des größten Elements in items und des Elements selbst zurück.

43
MatthieuBizien

Diese Methode ermittelt den Index des maximalen Elements einer Iteration und erfordert keine externen Importe:

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

Der Index des Maximums einer Liste:

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

Wenn in lst doppelte Maximalwerte vorhanden sind, wird der Index des ersten gefundenen Maximalwerts zurückgegeben.

12
stupidsven

Ein weiterer Weg, um den Argmax zu erhalten, ist:

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

dies ist eine sehr schnelle und einfache Möglichkeit, die effiziente Version zu erhalten, nach der Sie suchen:

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

Hier ist es mit Ihren Artikeln zu zeigen, dass es funktioniert:

>>> 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]
1
Ryan Saxe

Es ist einfach, wenn Sie nicht versuchen, die Tatsache zu nutzen, dass die internen Bereichslisten sortiert sind

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

Es klingt wie Sie eine Funktion wünschen, die den Index des kleinsten Werts zurückgibt

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
0
Phil Reinhold

Ich bin nicht sicher, was passiert ist, aber ich denke, dass jeder etwas falsch ist. Ich mache es dafür verantwortlich, dass ich schlechte Arbeit geleistet habe, um das Problem zu erklären, das ich zu lösen versuche. Wie auch immer, hier ist, wie viel ich bekommen habe: 

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

Das bringt mich am meisten dahin, aber es bleibt noch zu tun, wenn eine Liste erschöpft ist. Sobald dies erledigt ist, sollte es trivial sein, diesen Generator zu einem Generator zu machen, da ich ihn einfach in eine Schleife stecken und nachgeben kann, und auch ohne viel zu viel Arbeit, kann dies dazu verwendet werden, eine effiziente Sortierung über Generatoren durchzuführen.

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

Die richtige Teilmenge der noch gültigen Elemente zu min zusammenstellen ist das Ticket. 

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                                           

Hingerichtet:

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

Ich kann feststellen, dass dies immer noch verbessert werden kann. Die idxs-Liste wird bei jeder Iteration neu erstellt. Das muss nicht sein, aber das verbessert nicht die asymptotische Bindung ... Natürlich muss man sich fragen, ob es uns wirklich um die Leistung geht, ob der Einsatz des Lambda auch eine gute Idee ist, obwohl ich das wirklich nicht mag Sehen Sie sich einen Weg, ohne min auseinander zu nehmen, was einfach ein Abstieg in den Wahnsinn ist. 

0
Steven Lu