resueltos recorrer lista elementos ejercicios ejemplo diccionarios diccionario dentro convertir agregar python search dictionary

recorrer - lista de diccionarios python



Python lista de búsqueda de diccionarios (16)

¿Alguna vez has probado el paquete de pandas? Es perfecto para este tipo de tareas de búsqueda y optimizado también.

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

He agregado un poco de evaluación comparativa a continuación para ilustrar los tiempos de ejecución más rápidos de los pandas en una escala mayor, es decir, más de 100k entradas:

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

Supongamos que tengo esto:

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

y buscando "Pam" como nombre, quiero recuperar el diccionario relacionado: {nombre: "Pam", edad: 7}

¿Cómo lograr esto?


Aquí hay una comparación que utiliza iterating throuhg list, filter + lambda o refactoring (si es necesario o válido para su caso) su código para dictados de dictados en lugar de lista de dictados

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

Y la salida es esta:

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

Conclusión: es evidente que tener un diccionario de dictados es la forma más eficiente de poder buscar en esos casos, donde sabe que solo buscará por ID. Curiosamente usar filtro es la solución más lenta.


Encontré este hilo cuando estaba buscando una respuesta a la misma pregunta. Aunque me doy cuenta de que es una respuesta tardía, pensé que podría contribuir en caso de que sea útil para alguien más:

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 __name__ == ''__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


Esta es una forma general de buscar un valor en una lista de diccionarios:

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


Esto me parece la forma más pitónica:

people = [ {''name'': "Tom", ''age'': 10}, {''name'': "Mark", ''age'': 5}, {''name'': "Pam", ''age'': 7} ] filter(lambda person: person[''name''] == ''Pam'', people)

resultado (devuelto como una lista en Python 2):

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

Nota: En Python 3, se devuelve un objeto de filtro.


La respuesta de @Frédéric Hamidi es genial. En Python 3.x, la sintaxis de .next() cambió ligeramente. Así, una ligera modificación:

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

Como se menciona en los comentarios de @Matt, puede agregar un valor predeterminado como tal:

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


Mi primer pensamiento sería que tal vez desee considerar la creación de un diccionario de estos diccionarios ... si, por ejemplo, lo buscaría más de un pequeño número de veces.

Sin embargo, eso podría ser una optimización prematura. ¿Qué estaría mal 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]


Para agregar solo un poquito a @ FrédéricHamidi.

En caso de que no esté seguro de que haya una clave en la lista de dictados, algo como esto ayudaría:

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


Probé varios métodos para revisar una lista de diccionarios y devolver los diccionarios donde la clave x tiene un cierto valor.

Resultados:

  • Velocidad: comprensión de lista> expresión del generador >> iteración de lista normal >>> filtro.
  • Todas las escalas son lineales con el número de dictados en la lista (tamaño de lista 10x -> 10x tiempo).
  • Las claves por diccionario no afectan la velocidad significativamente para grandes cantidades (miles) de claves. Por favor, vea este gráfico que calculé: https://imgur.com/a/quQzv (los nombres de los métodos se encuentran a continuación).

Todas las pruebas realizadas 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

Resultados:

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


Puede utilizar una lista de comprensión :

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


Puedes usar una expresión generadora :

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


Tienes que pasar por todos los elementos de la lista. No hay un atajo!

A menos que en algún otro lugar guarde un diccionario de los nombres que apunten a los elementos de la lista, pero luego tendrá que ocuparse de las consecuencias de sacar un elemento de su lista.


Simplemente utilizando la lista de comprensión:

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

Código de muestra:

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


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


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]

Esta es una manera ...


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