2008-10-28 21 views
6

Wyobraźmy mam tych wykazów python:Mapa dwie listy w jedną listę słowników

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

istnieje bezpośredni lub przynajmniej prosty sposób, aby produkować następującą listę słowników?

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

Odpowiedz

13

Oto sposób błyskawiczny

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

Używanie l (małe litery ell) jako nazwy zmiennej to śmiertelne naruszenie pep8. Twoja licencja Pythoning zostaje niniejszym odwołana! ;) – ddaa

+0

Dziękuję Toni! wyjdziesz za mnie !? Zaznaczam twoją odpowiedź jako zaakceptowaną, ponieważ jest ona (teraz) najprostszym i łatwym do odczytania IMHO. –

+0

Użyj suwaka i części krokowej operatora plasterka, aby umieścić to wszystko w jednym zrozumieniu listy: [dykt (zip (klucze, a)) dla zipa (wartości [:: 2], wartości [1 :: 2])] – jblocksom

2

głupi sposób, ale taki, który natychmiast przychodzi mi do głowy:

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

To faktycznie nie tworzy listy, ale po prostu daje elementy. –

+0

ok, zmodyfikujmy go nieco. – Cheery

+0

Po prostu użyj 'list (fields_from_list (keys, values))' –

2

zip prawie robi to, co chcesz; niestety, zamiast jeździć krótszą listą, pęka. Być może istnieje powiązana funkcja, która cyklicznie?

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

/EDIT: Oh, chcesz listy z dict. Następujące prace (podziękowania dla Petera):

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

Masz rację, funkcja podobna do zipa, której cykle mogłyby wystarczyć. –

+0

'itertools.cycle' powtórzy sekwencję. Więc 'dict (zip (itertools.cycle (keys), values)) powinien to zrobić. –

+0

Peter, dziękuję, ale właśnie spróbowałem bez powodzenia. Zwraca {'age': 33, 'name': 'Frank'} –

1

Oto moje proste podejście. Wydaje się być bliskie idei, którą miał @Cheery, z wyjątkiem tego, że niszczę listę wejściową.

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

Kolejny spróbować, chyba głupsze niż pierwsza:

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

Ale to do ciebie, aby zdecydować, czy jest to głupsze.

2

W odpowiedzi przez Konrad Rudolph

zip prawie robi to, co chcesz; niestety, zamiast jeździć krótszą listą, pęka. Być może istnieje powiązana funkcja, która cyklicznie?

Oto sposób:

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

nie będę nazwać pythonowy (myślę, że to zbyt mądry), ale może to być co szukasz.

Nie ma żadnych korzyści w kolarstwie listę keys korzystając itertools.cycle(), ponieważ każdy przechodzenie od keys odpowiada stworzeniu jednej dictionnary.

EDIT: Oto kolejny sposób:

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

Jest to o wiele bardziej pythonic: istnieje czytelna funkcja użyteczności z jasnego celu, a reszta kodu przepływa naturalnie z niej.

+0

Zmieniłem "/" -> "//". Tak więc kod stał się kompatybilny z Python 3.0 i 'od __future__ import division'. – jfs

3

To nie jest ładne, ale tu jest jeden-liner używając wyrażeń listowych, ZIP i intensyfikacja:

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

Działa tylko dla 'len (klucze) == 2'. – jfs

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

UG-LEEE. Nie chciałbym zobaczyć kodu, który wygląda tak. Ale wygląda to dobrze.

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) 

Jeszcze trochę brzydka, ale nazwy pomagają to zrozumieć.