2008-10-28 25 views
6

Imagínese que tengo estas listas Python:dos listas en una sola lista de diccionarios

keys = ['name', 'age'] 
values = ['Monty', 42, 'Matt', 28, 'Frank', 33] 

¿Existe un una manera sencilla, directa o, al menos, para producir la siguiente lista de los diccionarios?

[ 
    {'name': 'Monty', 'age': 42}, 
    {'name': 'Matt', 'age': 28}, 
    {'name': 'Frank', 'age': 33} 
] 

Respuesta

13

Esta es la forma de cremallera

def mapper(keys, values): 
    n = len(keys) 
    return [dict(zip(keys, values[i:i + n])) 
      for i in range(0, len(values), n)] 
+0

El uso de l (minúscula ell) como nombre de variable es una violación mortal pep8. ¡Su licencia de Pythoning queda revocada! ;) – ddaa

+0

¡Gracias Toni! Te casarías conmigo !? Marcó su respuesta como aceptada, ya que es (en este momento) el más simple y fácil de leer en mi humilde opinión. –

+0

Use zip y la parte del paso del operador de división para poner todo esto en una sola comprensión de la lista: [dict (zip (claves, a)) para un zip en blanco (valores [:: 2], valores [1 :: 2])] – jblocksom

2

manera mudo, pero que inmediatamente viene a la mente:

def fields_from_list(keys, values): 
    iterator = iter(values) 
    while True: 
     yield dict((key, iterator.next()) for key in keys) 

list(fields_from_list(keys, values)) # to produce a list. 
+0

Esto realmente no crea la lista, sino que simplemente cede los elementos. –

+0

ok, modifiquemos un poco. – Cheery

+0

Simplemente use 'list (fields_from_list (keys, values))' –

2

zip casi hace lo que quiere; desafortunadamente, en lugar de pedalear en la lista más corta, se rompe. Tal vez hay una función relacionada que ciclos?

$ python 
>>> keys = ['name', 'age'] 
>>> values = ['Monty', 42, 'Matt', 28, 'Frank', 33] 
>>> dict(zip(keys, values)) 
{'age': 42, 'name': 'Monty'} 

/EDIT: Ah, usted quiere una lista de dict. Las siguientes obras (gracias a Peter, también):

from itertoos import cycle 

keys = ['name', 'age'] 
values = ['Monty', 42, 'Matt', 28, 'Frank', 33] 

x = zip(cycle(keys), values) 
map(lambda a: dict(a), zip(x[::2], x[1::2])) 
+0

Tiene razón, una función tipo zip que cicla haría el truco. –

+0

'itertools.cycle' repetirá una secuencia. Entonces 'dict (zip (itertools.cycle (keys), values))' debería hacerlo. –

+0

Peter, gracias, pero acabo de intentarlo sin éxito. Devuelve {'edad': 33, 'nombre': 'Frank'} –

1

Aquí es mi enfoque simple. Parece estar cerca de la idea que tenía @Cheery, excepto que destruí la lista de entrada.

def pack(keys, values): 
    """This function destructively creates a list of dictionaries from the input lists.""" 
    retval = [] 
    while values: 
    d = {} 
    for x in keys: 
     d[x] = values.pop(0) 
    retval.append(d) 
    return retval 
1

Sin embargo, otro intento, tal vez más tonto que el primero:

def split_seq(seq, count): 
    i = iter(seq) 
    while True: 
     yield [i.next() for _ in xrange(count)] 

>>> [dict(zip(keys, rec)) for rec in split_seq(values, len(keys))] 
[{'age': 42, 'name': 'Monty'}, 
{'age': 28, 'name': 'Matt'}, 
{'age': 33, 'name': 'Frank'}] 

Pero le toca a usted decidir si es más tonto.

2

En la respuesta por Konrad Rudolph

postal casi hace lo que quiere; desafortunadamente, en lugar de pedalear en la lista más corta, se rompe. Tal vez hay una función relacionada que ciclos?

Aquí está una manera:

keys = ['name', 'age'] 
values = ['Monty', 42, 'Matt', 28, 'Frank', 33] 
iter_values = iter(values) 
[dict(zip(keys, iter_values)) for _ in range(len(values) // len(keys))] 

no lo llamaré Pythonic (creo que es demasiado inteligente), pero podría ser lo que están buscando.

no hay ningún beneficio en el ciclismo la lista keys usando itertools.cycle(), ya que cada recorrido de keys corresponde a la creación de una dictionnary.

EDIT: Aquí hay otra manera:

def iter_cut(seq, size): 
    for i in range(len(seq)/size): 
     yield seq[i*size:(i+1)*size] 

keys = ['name', 'age'] 
values = ['Monty', 42, 'Matt', 28, 'Frank', 33] 
[dict(zip(keys, some_values)) for some_values in iter_cut(values, len(keys))] 

Esto es mucho más Pythonic: hay una función de utilidad puede leer con un propósito claro, y el resto del código fluye naturalmente de ella.

+0

He cambiado '/' -> '//'. Por lo tanto, el código se convirtió en Python 3.0 y compatible con 'from __future__ import division'. – jfs

3

No es bonito, pero aquí está una sola línea usando una lista por comprensión, zip y paso a paso:

[dict(zip(keys, a)) for a in zip(values[::2], values[1::2])] 
+0

Funciona solo para 'len (keys) == 2'. – jfs

0
[dict(zip(keys,values[n:n+len(keys)])) for n in xrange(0,len(values),len(keys)) ] 

UG-LEEE. Odiaría ver un código que se vea así. Pero se ve bien.

def dictizer(keys, values): 
    steps = xrange(0,len(values),len(keys)) 
    bites = (values[n:n+len(keys)] for n in steps) 
    return (dict(zip(keys,bite)) for bite in bites) 

Todavía un poco feo, pero los nombres ayudan a darle sentido.

Cuestiones relacionadas