risposta-alla-domanda-sullo-sviluppo-web-bd.com

Elenco Python di ricerca dizionari

Supponiamo di avere questo:

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

e cercando "Pam" come nome, voglio recuperare il dizionario correlato: {nome: "Pam", età: 7}

Come ottenere questo?

294
Hellnar

Puoi usare un'espressione generator :

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

Questo mi sembra il modo più pitonico:

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

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

risultato (restituito come elenco in Python 2):

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

Nota: in Python 3, viene restituito un oggetto filtro. Quindi la soluzione python3 sarebbe:

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

@ La risposta di Frédéric Hamidi è grandiosa. In Python 3.x la sintassi per .next() cambia leggermente. Quindi una leggera modifica:

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

Come menzionato nei commenti di @Matt, puoi aggiungere un valore predefinito in questo modo:

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

Puoi usare una list comprehension :

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

Ho provato vari metodi per esaminare un elenco di dizionari e restituire i dizionari in cui la chiave x ha un determinato valore. 

Risultati: 

  • Velocità: list comprehension> espressione del generatore >> lista normale iterazione >>> filtro. 
  • Tutte le scale sono lineari con il numero di dadi nell'elenco (dimensioni dell'elenco 10x -> 10 volte l'ora). 
  • Le chiavi per dizionario non influenzano significativamente la velocità per grandi quantità (migliaia) di chiavi. Si prega di vedere questo grafico che ho calcolato: https://imgur.com/a/quQzv (i nomi dei metodi vedi sotto). 

Tutti i test sono stati eseguiti con 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

Risultati:

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

Per aggiungere un pochino a @ FrédéricHamidi.

Nel caso in cui non si sia certi che una chiave sia presente nell'elenco di dicts, qualcosa del genere potrebbe aiutare:

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

Hai mai provato il pacchetto panda? È perfetto per questo tipo di attività di ricerca e anche ottimizzato.

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

Ho aggiunto un po 'di benchmarking qui sotto per illustrare i runtime più veloci dei panda su una scala più ampia, vale a dire 100k + voci:

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]

Questo è un modo ...

6
Niclas Nilsson

Questo è un modo generale di cercare un valore in un elenco di dizionari:

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

Il mio primo pensiero sarebbe che potresti voler prendere in considerazione la creazione di un dizionario di questi dizionari ... se, ad esempio, avresti dovuto cercarlo più che in un numero limitato di volte.

Tuttavia potrebbe essere un'ottica prematura. Cosa sarebbe sbagliato con:

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

Semplicemente usando la list comprehension:

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

Codice di esempio:

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

Devi passare attraverso tutti gli elementi della lista. Non c'è una scorciatoia!

A meno che da qualche altra parte mantieni un dizionario con i nomi che puntano agli elementi della lista, ma poi devi prenderti cura delle conseguenze dello schioccare un elemento dalla tua lista.

0
jimifiki

Puoi provare questo:

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

Ho trovato questo thread quando cercavo una risposta alla stessa domanda Mentre mi rendo conto che è una risposta tardiva, ho pensato di farlo Contribuendolo nel caso fosse utile a chiunque altro:

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.

Penso che tu possa usare Panda per affrontare questo.

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

Emette:

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

I vantaggi sono:

  • Panda che fornisce elaborazione dati ad alte prestazioni, il che significa che se si dispone di un set di dati di grandi dimensioni, la ricerca non consumerà molto tempo.
  • La struttura dei dati è facile da usare e puoi trattare i tuoi dati come una tabella per ulteriori analisi.
0
lazy_frog

Ecco un confronto usando iterando l'elenco, usando filter + lambda o refactoring (se necessario o valido per il tuo caso) il tuo codice per dettare dict piuttosto che list of dicts

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

E l'output è questo:

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

Conclusione: Chiaramente avere un dizionario di dicts è il modo più efficiente per essere in grado di cercare in quei casi, dove sai dire che cercheresti solo per ID. soluzione.

0
Kőhalmy Zoltán