Mam listę dyktand:
list = [{'id':'1234','name':'Jason'},
{'id':'2345','name':'Tom'},
{'id':'3456','name':'Art'}]
Jak skutecznie znaleźć pozycję indeksu [0], [1] lub [2], dopasowując do name = „Tom”?
Gdyby to była lista jednowymiarowa, mógłbym zrobić list.index (), ale nie jestem pewien, jak postępować, przeszukując wartości dykt na liście.
{ 'Jason': {'id': '1234'}, 'Tom': {'id': '1245'}, ...}
?){'1234': {'name': 'Jason'}, ...}
. Nie żeby to pomogło w tym przypadku użycia.Odpowiedzi:
lst = [{'id':'1234','name':'Jason'}, {'id':'2345','name':'Tom'}, {'id':'3456','name':'Art'}] tom_index = next((index for (index, d) in enumerate(lst) if d["name"] == "Tom"), None) # 1
Jeśli chcesz wielokrotnie pobierać dane z nazwy, powinieneś indeksować je po nazwie (używając słownika), w ten sposób operacje get będą miały czas O (1). Pomysł:
def build_dict(seq, key): return dict((d[key], dict(d, index=index)) for (index, d) in enumerate(seq)) info_by_name = build_dict(lst, key="name") tom_info = info_by_name.get("Tom") # {'index': 1, 'id': '2345', 'name': 'Tom'}
źródło
next()
do tego wydaje mi się dziwne), celem jest po prostu uzyskanie indeksu. Ponadto podnosi to StopIteration, podczas gdylst.index()
metoda Pythona podnosi ValueError.first()
brzmi lepiej. Zawsze możesz spróbować / z wyjątkiem StopIteration i podnieść ValueError, aby obiekt wywołujący miał spójność. Alternatywnie ustawnext()
wartość domyślną na -1.SyntaxError: Generator expression must be parenthesized if not sole argument
kiedy to robię.next((index for (index, d) in enumerate(lst) if d["name"] == "Tom"), None)
Prosta, czytelna wersja to
def find(lst, key, value): for i, dic in enumerate(lst): if dic[key] == value: return i return -1
źródło
str.find()
Ładnie naśladuje również zachowanie . Możesz też toindex()
sprawdzić i podbićValueError
zamiast zwracać -1, jeśli wolisz.Nie będzie to wydajne, ponieważ musisz przejść się po liście, sprawdzając każdy element na niej (O (n)). Jeśli chcesz wydajności, możesz użyć dyktowania . Jeśli chodzi o pytanie, oto jeden możliwy sposób, aby go znaleźć (jeśli jednak chcesz trzymać się tej struktury danych, w rzeczywistości bardziej wydajne jest użycie generatora, jak napisał Brent Newey w komentarzach; zobacz także odpowiedź toklanda):
>>> L = [{'id':'1234','name':'Jason'}, ... {'id':'2345','name':'Tom'}, ... {'id':'3456','name':'Art'}] >>> [i for i,_ in enumerate(L) if _['name'] == 'Tom'][0] 1
źródło
Wydaje się najbardziej logiczne użycie kombinacji filtr / indeks:
names=[{}, {'name': 'Tom'},{'name': 'Tony'}] names.index(filter(lambda n: n.get('name') == 'Tom', names)[0]) 1
A jeśli uważasz, że może być wiele dopasowań:
[names.index(n) for item in filter(lambda n: n.get('name') == 'Tom', names)] [1]
źródło
Oto funkcja, która znajduje pozycję indeksu słownika, jeśli istnieje.
dicts = [{'id':'1234','name':'Jason'}, {'id':'2345','name':'Tom'}, {'id':'3456','name':'Art'}] def find_index(dicts, key, value): class Null: pass for i, d in enumerate(dicts): if d.get(key, Null) == value: return i else: raise ValueError('no dict with the key and value combination found') print find_index(dicts, 'name', 'Tom') # 1 find_index(dicts, 'name', 'Ensnare') # ValueError: no dict with the key and value combination found
źródło
Odpowiedź oferowana przez @faham jest ładną linijką, ale nie zwraca indeksu do słownika zawierającego wartość. Zamiast tego zwraca sam słownik. Oto prosty sposób, aby uzyskać: Listę indeksów, jeden lub więcej, jeśli jest więcej niż jeden, lub pustą listę, jeśli nie ma:
list = [{'id':'1234','name':'Jason'}, {'id':'2345','name':'Tom'}, {'id':'3456','name':'Art'}] [i for i, d in enumerate(list) if 'Tom' in d.values()]
Wynik:
>>> [1]
W tym podejściu podoba mi się to, że dzięki prostej edycji można uzyskać listę zarówno indeksów, jak i słowników jako krotki. To jest problem, który musiałem rozwiązać i znalazłem te odpowiedzi. Poniżej dodałem zduplikowaną wartość w innym słowniku, aby pokazać, jak to działa:
list = [{'id':'1234','name':'Jason'}, {'id':'2345','name':'Tom'}, {'id':'3456','name':'Art'}, {'id':'4567','name':'Tom'}] [(i, d) for i, d in enumerate(list) if 'Tom' in d.values()]
Wynik:
>>> [(1, {'id': '2345', 'name': 'Tom'}), (3, {'id': '4567', 'name': 'Tom'})]
To rozwiązanie znajduje wszystkie słowniki zawierające słowo „Tom” w dowolnej z ich wartości.
źródło
Jedna wkładka !?
elm = ([i for i in mylist if i['name'] == 'Tom'] or [None])[0]
źródło
Potrzebowałem bardziej ogólnego rozwiązania, aby uwzględnić możliwość wielu słowników na liście mających wartość kluczową oraz prostą implementację przy użyciu funkcji rozumienia list:
dict_indices = [i for i, d in enumerate(dict_list) if d[dict_key] == key_value]
źródło
Dla danej iterowalności
more_itertools.locate
zwraca pozycje pozycji, które spełniają predykat.import more_itertools as mit iterable = [ {"id": "1234", "name": "Jason"}, {"id": "2345", "name": "Tom"}, {"id": "3456", "name": "Art"} ] list(mit.locate(iterable, pred=lambda d: d["name"] == "Tom")) # [1]
more_itertools
to zewnętrzna biblioteka, która implementuje receptury itertools wśród innych przydatnych narzędzi.źródło
def search(itemID,list): return[i for i in list if i.itemID==itemID]
źródło