Suche nach Wörterbüchern in Python-Liste

Lesezeit: 6 Minuten

Benutzer-Avatar
Hellnar

Angenommen ich habe das:

[
  {"name": "Tom", "age": 10},
  {"name": "Mark", "age": 5},
  {"name": "Pam", "age": 7}
]

und indem ich “Pam” als Namen suche, möchte ich das zugehörige Wörterbuch abrufen: {name: "Pam", age: 7}

Wie erreicht man das?

Benutzer-Avatar
Frédéric Hamidi

Sie können eine verwenden Generatorausdruck:

>>> dicts = [
...     { "name": "Tom", "age": 10 },
...     { "name": "Mark", "age": 5 },
...     { "name": "Pam", "age": 7 },
...     { "name": "Dick", "age": 12 }
... ]

>>> next(item for item in dicts if item["name"] == "Pam")
{'age': 7, 'name': 'Pam'}

Wenn Sie damit umgehen müssen, dass das Element nicht vorhanden ist, können Sie das tun, was Benutzer Matt in seinem Kommentar vorgeschlagen hat, und einen Standard mit einer etwas anderen API bereitstellen:

next((item for item in dicts if item["name"] == "Pam"), None)

Und um den Index des Elements anstelle des Elements selbst zu finden, können Sie aufzählen() Die Liste:

next((i for i, item in enumerate(dicts) if item["name"] == "Pam"), None)

  • Nur um jemandem etwas Zeit zu sparen, wenn Sie einen Standardwert für das Ereignis benötigen, “Pam” ist einfach nicht in der Liste: next((item for item in dicts if item[“name”] == “Pam”), keine)

    – Matt

    27. November 2012 um 22:08 Uhr


  • Wie wäre es mit [item for item in dicts if item["name"] == "Pam"][0]?

    – Möberg

    9. Oktober 2014 um 11:30 Uhr

  • @Moberg, das ist immer noch ein Listenverständnis, daher wird die gesamte Eingabesequenz unabhängig von der Position des übereinstimmenden Elements durchlaufen.

    – Frédéric Hamidi

    9. Oktober 2014 um 12:02 Uhr

  • Dadurch wird ein Stoppiterationsfehler ausgelöst, wenn der Schlüssel nicht im Wörterbuch vorhanden ist

    – Kishan Mehta

    5. Juni 2018 um 12:25 Uhr

  • @Siemkowski: dann hinzufügen enumerate() um einen laufenden Index zu generieren: next(i for i, item in enumerate(dicts) if item["name"] == "Pam").

    – Martijn Pieters

    22. November 2018 um 12:56 Uhr

Benutzer-Avatar
PaoloC

Das sieht für mich am pythonischsten aus:

people = [
{'name': "Tom", 'age': 10},
{'name': "Mark", 'age': 5},
{'name': "Pam", 'age': 7}
]

filter(lambda person: person['name'] == 'Pam', people)

Ergebnis (als Liste in Python 2 zurückgegeben):

[{'age': 7, 'name': 'Pam'}]

Hinweis: In Python 3 wird ein Filterobjekt zurückgegeben. Die Python3-Lösung wäre also:

list(filter(lambda person: person['name'] == 'Pam', people))

  • Es ist erwähnenswert, dass diese Antwort eine Liste mit allen Übereinstimmungen für „Pam“ in Personen zurückgibt. Alternativ könnten wir eine Liste aller Personen erhalten, die nicht „Pam“ sind, indem wir den Vergleichsoperator in != ändern. +1

    – Onema

    12. November 2015 um 22:25 Uhr

  • Erwähnenswert ist auch, dass das Ergebnis ein Filterobjekt ist, keine Liste – wenn Sie Dinge wie verwenden möchten len()du musst anrufen list() zuerst auf das Ergebnis. Oder: stackoverflow.com/questions/19182188/…

    – wasabigeek

    21. Dezember 2017 um 16:06 Uhr


  • @wasabigeek das sagt mein Python 2.7: people = [ {‘name’: “Tom”, ‘age’: 10}, {‘name’: “Mark”, ‘age’: 5}, {‘name’: “Pam”, ‘age’: 7} ] r = filter(lambda Person: Person[‘name’] == ‘Pam’, Leute) type(r) list Also r ist ein list

    – PaoloC

    26. Dezember 2017 um 14:32 Uhr


  • Listenverständnisse gelten als pythonischer als map/filter/reduce: stackoverflow.com/questions/5426754/google-python-style-guide

    – jrc

    11. November 2019 um 12:58 Uhr

  • Holen Sie sich das erste Spiel: next(filter(lambda x: x['name'] == 'Pam', dicts))

    – xgMz

    12. Dezember 2019 um 19:24 Uhr

Benutzer-Avatar
Mike N

@ Frédéric Hamidis Antwort ist großartig. In Python 3.x ist die Syntax für .next() leicht verändert. Daher eine kleine Modifikation:

>>> dicts = [
     { "name": "Tom", "age": 10 },
     { "name": "Mark", "age": 5 },
     { "name": "Pam", "age": 7 },
     { "name": "Dick", "age": 12 }
 ]
>>> next(item for item in dicts if item["name"] == "Pam")
{'age': 7, 'name': 'Pam'}

Wie in den Kommentaren von @Matt erwähnt, können Sie einen Standardwert als solchen hinzufügen:

>>> next((item for item in dicts if item["name"] == "Pam"), False)
{'name': 'Pam', 'age': 7}
>>> next((item for item in dicts if item["name"] == "Sam"), False)
False
>>>

  • Dies ist die beste Antwort für Python 3.x. Wenn Sie ein bestimmtes Element aus den Diktaten benötigen, z. B. das Alter, können Sie Folgendes schreiben: next((item.get(‘age’) for item in dicts if item[“name”] == “Pam”), falsch)

    – Flüsterer

    9. Januar 2019 um 7:44 Uhr

Sie können eine verwenden Listenverständnis:

def search(name, people):
    return [element for element in people if element['name'] == name]

Ich habe verschiedene Methoden getestet, um eine Liste von Wörterbüchern durchzugehen und die Wörterbücher zurückzugeben, in denen der Schlüssel x einen bestimmten Wert hat.

Ergebnisse:

  • Geschwindigkeit: Listenverständnis > Generatorausdruck >> normale Listeniteration >>> Filter.
  • Alle skalieren linear mit der Anzahl der Diktate in der Liste (10x Listengröße -> 10x Zeit).
  • Die Schlüssel pro Wörterbuch wirken sich bei großen Mengen (Tausenden) von Schlüsseln nicht wesentlich auf die Geschwindigkeit aus. Bitte sehen Sie sich diese Grafik an, die ich berechnet habe: https://imgur.com/a/quQzv (Methodennamen siehe unten).

Alle Tests mit gemacht Python 3.6.4, W7x64.

from random import randint
from timeit import timeit


list_dicts = []
for _ in range(1000):     # number of dicts in the list
    dict_tmp = {}
    for i in range(10):   # number of keys for each dict
        dict_tmp[f"key{i}"] = randint(0,50)
    list_dicts.append( dict_tmp )



def a():
    # normal iteration over all elements
    for dict_ in list_dicts:
        if dict_["key3"] == 20:
            pass

def b():
    # use 'generator'
    for dict_ in (x for x in list_dicts if x["key3"] == 20):
        pass

def c():
    # use 'list'
    for dict_ in [x for x in list_dicts if x["key3"] == 20]:
        pass

def d():
    # use 'filter'
    for dict_ in filter(lambda x: x['key3'] == 20, list_dicts):
        pass

Ergebnisse:

1.7303 # normal list iteration 
1.3849 # generator expression 
1.3158 # list comprehension 
7.7848 # filter

  • Ich habe die Funktion z() hinzugefügt, die next implementiert, wie oben von Frédéric Hamidi gezeigt. Hier sind die Ergebnisse des Py-Profils.

    – Leon

    24. März 2019 um 1:53 Uhr

Benutzer-Avatar
Rick Robinson

people = [
{'name': "Tom", 'age': 10},
{'name': "Mark", 'age': 5},
{'name': "Pam", 'age': 7}
]

def search(name):
    for p in people:
        if p['name'] == name:
            return p

search("Pam")

  • Ich habe die Funktion z() hinzugefügt, die next implementiert, wie oben von Frédéric Hamidi gezeigt. Hier sind die Ergebnisse des Py-Profils.

    – Leon

    24. März 2019 um 1:53 Uhr

Haben Sie schon einmal das Pandas-Paket ausprobiert? Es ist perfekt für diese Art von Suchaufgabe und auch optimiert.

import pandas as pd

listOfDicts = [
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]

# Create a data frame, keys are used as column headers.
# Dict items with the same key are entered into the same respective column.
df = pd.DataFrame(listOfDicts)

# The pandas dataframe allows you to pick out specific values like so:

df2 = df[ (df['name'] == 'Pam') & (df['age'] == 7) ]

# Alternate syntax, same thing

df2 = df[ (df.name == 'Pam') & (df.age == 7) ]

Ich habe unten ein wenig Benchmarking hinzugefügt, um die schnelleren Laufzeiten von Pandas in größerem Maßstab zu veranschaulichen, dh über 100.000 Einträge:

setup_large="dicts = [];\
[dicts.extend(({ "name": "Tom", "age": 10 },{ "name": "Mark", "age": 5 },\
{ "name": "Pam", "age": 7 },{ "name": "Dick", "age": 12 })) for _ in range(25000)];\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(dicts);"

setup_small="dicts = [];\
dicts.extend(({ "name": "Tom", "age": 10 },{ "name": "Mark", "age": 5 },\
{ "name": "Pam", "age": 7 },{ "name": "Dick", "age": 12 }));\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(dicts);"

method1 = '[item for item in dicts if item["name"] == "Pam"]'
method2 = 'df[df["name"] == "Pam"]'

import timeit
t = timeit.Timer(method1, setup_small)
print('Small Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_small)
print('Small Method Pandas: ' + str(t.timeit(100)))

t = timeit.Timer(method1, setup_large)
print('Large Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_large)
print('Large Method Pandas: ' + str(t.timeit(100)))

#Small Method LC: 0.000191926956177
#Small Method Pandas: 0.044392824173
#Large Method LC: 1.98827004433
#Large Method Pandas: 0.324505090714

  • und method3 = “””df.query(“name == ‘Pam'”)”””, ist zwar etwas langsamer als Methode 2 für kleine Datensätze (immer noch 2 Größenordnungen schneller als LC), aber auf meinem Computer doppelt so schnell für den größeren Datensatz

    – Emmagras

    9. Februar um 13:25 Uhr

1131360cookie-checkSuche nach Wörterbüchern in Python-Liste

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy