wake-up-neo.com

Python - Findet den Index eines Elements in einer Listenliste

Ich habe eine Liste von Listen:

colours=[["#660000","#863030","#ba4a4a","#de7e7e","#ffaaaa"],["#a34b00","#d46200","#ff7a04","#ff9b42","#fec28d"],["#dfd248","#fff224","#eefd5d","#f5ff92","#f9ffbf"],["#006600","#308630","#4aba4a","#7ede7e","#aaffaa"]]

was der sauberste Weg ist, um die Liste zu durchsuchen und die Position eines der Elemente, z. "#660000"?

Ich habe mir die Indexmethode angesehen, aber das scheint die Liste nicht innerhalb der Liste zu entpacken.

postion=colours.index("#660000")

gibt: ValueError: ['#660000'] is not in list, nicht [0][0], wie ich erwartet habe ...

10
Jay Gattuso

Ich würde so etwas machen:

[(i, colour.index(c))
 for i, colour in enumerate(colours)
 if c in colour]

Dies gibt eine Liste von Tupeln zurück, bei denen der erste Index die Position in der ersten Liste und der zweite Index die Position in der zweiten Liste ist (Hinweis: c ist die Farbe, nach der Sie suchen, d. H. "#660000").

Für das Beispiel in der Frage lautet der zurückgegebene Wert:

[(0, 0)]

Wenn Sie nur die erste Position suchen müssen, an der die Farbe faul gefunden wird, können Sie Folgendes verwenden:

next(((i, colour.index(c))
      for i, colour in enumerate(colours)
      if c in colour),
     None)

Dadurch wird der Tupel für das erste gefundene Element zurückgegeben oder None, wenn kein Element gefunden wird (Sie können auch das oben angegebene None-Argument entfernen. In diesem Fall wird eine StopIteration-Ausnahme ausgelöst, wenn kein Element gefunden wird).

Bearbeiten: Wie @RikPoggi richtig feststellt, führt dies bei einer hohen Anzahl von Übereinstimmungen zu Mehraufwand, da colour zweimal wiederholt wird, um c zu finden. Ich nahm an, dass dies für eine geringe Anzahl von Übereinstimmungen angemessen ist und eine Antwort auf einen einzelnen Ausdruck enthält. Um dies zu vermeiden, können Sie jedoch auch eine Methode definieren, die dieselbe Idee wie folgt verwendet:

def find(c):
    for i, colour in enumerate(colours):
        try:
            j = colour.index(c)
        except ValueError:
            continue
        yield i, j

matches = [match for match in find('#660000')]

Da find ein Generator ist, können Sie ihn wie im obigen Beispiel mit next verwenden, um beim ersten Treffer anzuhalten und die Suche zu überspringen.

15
jcollado

Mit enumerate() können Sie eine Funktion wie diese schreiben:

def find(target):
    for i,lst in enumerate(colours):
        for j,color in enumerate(lst):
            if color == "#660000":
                return (i, j)
    return (None, None)
8
Rik Poggi

Wenn Sie die Ziel-Unterliste zweimal durchlaufen möchten, scheint der beste (und der beste Pythonic-Weg) eine Schleife:

def find_in_sublists(lst, value):
    for sub_i, sublist in enumerate(lst):
        try:
            return (sub_i, sublist.index(value))
        except ValueError:
            pass

    raise ValueError('%s is not in lists' % value)
4
bereal

Es wäre vielleicht einfacher mit numpy :

>>> import numpy
>>> ar = numpy.array(colours)
>>> numpy.where(ar=="#fff224")
(array([2]), array([1]))

Wie Sie sehen, erhalten Sie ein Tupel mit allen Zeilen- und Spaltenindizes.

3
Rik Poggi

In Python 3 habe ich dieses Muster verwendet:

CATEGORIES = [   
    [1, 'New', 'Sub-Issue', '', 1],
    [2, 'Replace', 'Sub-Issue', '', 5],
    [3, 'Move', 'Sub-Issue', '', 7],
]

# return single item by indexing the sub list
next(c for c in CATEGORIES if c[0] == 2)
0
Aaron Lelevier