it-swarm.com.de

Python-Liste der Wörterbücher suchen

Angenommen, ich habe folgendes:

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

und durch die Suche nach "Pam" als Namen möchte ich das verwandte Wörterbuch abrufen: {Name: "Pam", Alter: 7}

Wie kann ich das erreichen?

294
Hellnar

Sie können einen Generator-Ausdruck verwenden :

>>> 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'}
342

Dies sieht für mich am pythonicsten Weg:

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))
131
PaoloC

@ Frédéric Hamidis Antwort ist großartig. In Python 3.x hat sich die Syntax für .next() etwas geändert. Also eine leichte 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
>>>
47
Mike N

Sie können ein Listenverständnis verwenden :

def search(name, people):
    return [element for element in people if element['name'] == name]
33
user334856
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")
21
satoru

Ich habe verschiedene Methoden getestet, um eine Liste von Wörterbüchern durchzugehen und Wörterbücher zurückzugeben, bei 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 beeinflussen die Geschwindigkeit für große Mengen (Tausende) von Schlüsseln nicht signifikant. Bitte sehen Sie diese Grafik, die ich berechnet habe: https://imgur.com/a/quQzv (Methodennamen siehe unten). 

Alle Tests wurden mit Python 3.6 .4, W7x64 durchgeführt.

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
13
user136036

Um @ FrédéricHamidi ein kleines bisschen hinzuzufügen.

Falls Sie sich nicht sicher sind, ob ein Schlüssel in der Liste der Diktate enthalten ist, könnte dies wie folgt helfen:

next((item for item in dicts if item.get("name") and item["name"] == "Pam"), None)
9
Drazen Urch

Haben Sie das Pandapaket schon einmal 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 einem größeren Maßstab darzustellen, d.

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
7
abby sobh
names = [{'name':'Tom', 'age': 10}, {'name': 'Mark', 'age': 5}, {'name': 'Pam', 'age': 7}]
resultlist = [d    for d in names     if d.get('name', '') == 'Pam']
first_result = resultlist[0]

Dies ist eine Möglichkeit ...

6
Niclas Nilsson

Dies ist eine allgemeine Methode zum Suchen eines Werts in einer Liste von Wörterbüchern:

def search_dictionaries(key, value, list_of_dictionaries):
    return [element for element in list_of_dictionaries if element[key] == value]
6
ipegasus

Mein erster Gedanke wäre, dass Sie vielleicht ein Wörterbuch für diese Wörterbücher erstellen möchten, wenn Sie es zum Beispiel öfter suchen würden.

Dies kann jedoch eine vorzeitige Optimierung sein. Was wäre falsch mit:

def get_records(key, store=dict()):
    '''Return a list of all records containing name==key from our store
    '''
    assert key is not None
    return [d for d in store if d['name']==key]
4
Jim Dennis
dicts=[
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]

from collections import defaultdict
dicts_by_name=defaultdict(list)
for d in dicts:
    dicts_by_name[d['name']]=d

print dicts_by_name['Tom']

#output
#>>>
#{'age': 10, 'name': 'Tom'}
3
robert king

Einfach Listenverständnis verwenden:

[i for i in dct if i['name'] == 'Pam'][0]

Beispielcode:

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

print([i for i in dct if i['name'] == 'Pam'][0])

> {'age': 7, 'name': 'Pam'}
1
Teoretic

Sie müssen alle Elemente der Liste durchgehen. Es gibt keine Abkürzung!

Sofern nicht anders angegeben, führen Sie ein Wörterbuch mit Namen, die auf die Elemente der Liste verweisen. Dann müssen Sie sich jedoch um die Konsequenzen kümmern, die sich aus dem Entfernen eines Elements aus Ihrer Liste ergeben.

0
jimifiki

Sie können dies versuchen:

''' lst: list of dictionaries '''
lst = [{"name": "Tom", "age": 10}, {"name": "Mark", "age": 5}, {"name": "Pam", "age": 7}]

search = raw_input("What name: ") #Input name that needs to be searched (say 'Pam')

print [ lst[i] for i in range(len(lst)) if(lst[i]["name"]==search) ][0] #Output
>>> {'age': 7, 'name': 'Pam'} 
0

Ich fand diesen Thread, als ich nach einer Antwort auf dieselbe -Frage suchte. Obwohl mir klar ist, dass es eine späte Antwort ist, dachte ich, ich würde es beitragen, falls es für alle anderen nützlich ist:

def find_dict_in_list(dicts, default=None, **kwargs):
    """Find first matching :obj:`dict` in :obj:`list`.

    :param list dicts: List of dictionaries.
    :param dict default: Optional. Default dictionary to return.
        Defaults to `None`.
    :param **kwargs: `key=value` pairs to match in :obj:`dict`.

    :returns: First matching :obj:`dict` from `dicts`.
    :rtype: dict

    """

    rval = default
    for d in dicts:
        is_found = False

        # Search for keys in dict.
        for k, v in kwargs.items():
            if d.get(k, None) == v:
                is_found = True

            else:
                is_found = False
                break

        if is_found:
            rval = d
            break

    return rval


if __== '__main__':
    # Tests
    dicts = []
    keys = 'spam eggs shrubbery knight'.split()

    start = 0
    for _ in range(4):
        dct = {k: v for k, v in Zip(keys, range(start, start+4))}
        dicts.append(dct)
        start += 4

    # Find each dict based on 'spam' key only.  
    for x in range(len(dicts)):
        spam = x*4
        assert find_dict_in_list(dicts, spam=spam) == dicts[x]

    # Find each dict based on 'spam' and 'shrubbery' keys.
    for x in range(len(dicts)):
        spam = x*4
        assert find_dict_in_list(dicts, spam=spam, shrubbery=spam+2) == dicts[x]

    # Search for one correct key, one incorrect key:
    for x in range(len(dicts)):
        spam = x*4
        assert find_dict_in_list(dicts, spam=spam, shrubbery=spam+1) is None

    # Search for non-existent dict.
    for x in range(len(dicts)):
        spam = x+100
        assert find_dict_in_list(dicts, spam=spam) is None
0
Doug R.

Ich denke, Sie können Pandas verwenden, um damit umzugehen.

import pandas as pd

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

person_df = pd.DataFrame(person_list)
person_df[person_df["name"] == "Pam"].to_dict('records')

Es gibt aus:

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

Die Vorteile sind:

  • Pandas bieten leistungsstarke Datenverarbeitung. Wenn Sie also über einen großen Datenbestand verfügen, würde die Suche nicht viel Zeit in Anspruch nehmen.
  • Die Datenstruktur ist benutzerfreundlich und Sie können Ihre Daten zur weiteren Analyse als Tabelle behandeln.
0
lazy_frog

Hier ist ein Vergleich, indem Sie die Liste durchlaufen, Filter + Lambda verwenden oder (falls erforderlich oder in Ihrem Fall gültig) Ihren Code umwandeln, um Diktate anstelle von Diktierlisten anzugeben

import time

# Build list of dicts
list_of_dicts = list()
for i in range(100000):
    list_of_dicts.append({'id': i, 'name': 'Tom'})

# Build dict of dicts
dict_of_dicts = dict()
for i in range(100000):
    dict_of_dicts[i] = {'name': 'Tom'}


# Find the one with ID of 99

# 1. iterate through the list
lod_ts = time.time()
for elem in list_of_dicts:
    if elem['id'] == 99999:
        break
lod_tf = time.time()
lod_td = lod_tf - lod_ts

# 2. Use filter
f_ts = time.time()
x = filter(lambda k: k['id'] == 99999, list_of_dicts)
f_tf = time.time()
f_td = f_tf- f_ts

# 3. find it in dict of dicts
dod_ts = time.time()
x = dict_of_dicts[99999]
dod_tf = time.time()
dod_td = dod_tf - dod_ts


print 'List of Dictionries took: %s' % lod_td
print 'Using filter took: %s' % f_td
print 'Dict of Dicts took: %s' % dod_td

Und die Ausgabe ist folgende:

List of Dictionries took: 0.0099310874939
Using filter took: 0.0121960639954
Dict of Dicts took: 4.05311584473e-06

Fazit: Ein Wörterbuch mit Diktaten ist eindeutig der effizienteste Weg, um in den Fällen suchen zu können, in denen Sie wissen, dass Sie nur mit id suchen Lösung.

0