2009-09-29 20 views
10

Tengo una gran colección de (p, q) tuplas que me gustaría convertir en un diccionario de listas donde el primer elemento de cada tupla es una clave que indexa una lista que contiene q .Combinación de diccionarios de listas en Python

Ejemplo:

Original List: (1, 2), (1, 3), (2, 3) 
Resultant Dictionary: {1:[2, 3], 2:[3]} 

Además, me gustaría combinar eficientemente estos diccionarios.

Ejemplo:

Original Dictionaries: {1:[2, 3], 2:[3]}, {1:[4], 3:[1]} 
Resultant Dictionary: {1:[2, 3, 4], 2:[3], 3:[1]} 

Estas operaciones residen dentro de un bucle interno, por lo que se prefieren que sean lo más rápido posible.

Gracias de antemano

Respuesta

14

Si se ordena la lista de tuplas, itertools.groupby, según lo sugerido por @gnibbler, no es una mala alternativa a defaultdict, pero tiene que ser utilizado de manera diferente de lo que sugirió:

import itertools 
import operator 

def lot_to_dict(lot): 
    key = operator.itemgetter(0) 
    # if lot's not sorted, you also need...: 
    # lot = sorted(lot, key=key) 
    # NOT in-place lot.sort to avoid changing it! 
    grob = itertools.groupby(lot, key) 
    return dict((k, [v[1] for v in itr]) for k, itr in grob) 

Por "fusión" de las listas dicts en un nuevo d.o.l ...:

def merge_dols(dol1, dol2): 
    keys = set(dol1).union(dol2) 
    no = [] 
    return dict((k, dol1.get(k, no) + dol2.get(k, no)) for k in keys) 

estoy dando [] un apodo no inútilmente para evitar la construcción de una gran cantidad de listas vacías, teniendo en cuenta que el rendimiento es importante. Si los juegos de llaves de los DOLS se solapan sólo modestamente, más rápido sería:

def merge_dols(dol1, dol2): 
    result = dict(dol1, **dol2) 
    result.update((k, dol1[k] + dol2[k]) 
       for k in set(dol1).intersection(dol2)) 
    return result 

ya que este utiliza la lista-encadenamiento sólo para llaves superpuestas - así, si son pocos, que será más rápido.

+0

2016 y '' merge_dols''' v.1 suena fantástico y elegante, ¡gracias! v.2, sin embargo, utiliza un [método no aceptable] (http://stackoverflow.com/questions/38987/how-to-merge-two-python-dictionaries-in-a-single-expression/39858#39858) : '' 'dict (dol1, ** dol2)' '' – raratiru

3

defaltdict al rescate (como de costumbre)

from collections import defaultdict 
my_dict = defaultdict(list) 

for key,value in original_list: 
    my_dict[key].append(value) 

La combinación de los dos dicts se puede hacer así (Tenga en cuenta que los duplicados se conservarán):

for key,value in orig_dict: 
    new_dict[key].extend(value) 
+0

Creo que necesitas para .append() elementos de las tuplas. – Noah

+0

su segundo ciclo no está operativo – SilentGhost

3

collections.defaultdict funciona de esta manera:

from collections import defaultdict 
dic = defaultdict(list) 
for i, j in tuples: 
    dic[i].append(j) 

similar para los dicts:

a, b = {1:[2, 3], 2:[3]}, {1:[4], 3:[1]} 
de = defaultdict(list, a) 
for i, j in b.items(): 
    de[i].extend(j) 
0

Aquí es el estilo iterador de hacerlo

 
>>> mylist=[(1, 2), (1, 3), (2, 3)] 
>>> from itertools import groupby 
>>> from operator import itemgetter 
>>> mylist=[(1, 2), (1, 3), (2, 3)] 
>>> groupby(mylist,itemgetter(0)) 

>>> list(_) 
[(1, <itertools._grouper object at 0xb7d402ec>), (2, <itertools._grouper object at 0xb7c716ec>)] 
+0

eso no es lo que OP pidió, ¿o sí? – SilentGhost

0

que querían estos hecho en una línea sólo por diversión:

>>> from itertools import groupby 
>>> t=(1, 2), (1, 3), (2, 3) 
>>> [(i,[x for _,x in list(f)]) for i,f in groupby(sorted(t),lambda t: t[0])] 
[(1, [2, 3]), (2, [3])] 
>>> b={1:[2, 3], 2:[3]}, {1:[4], 3:[1]} 
>>> dict([(key,sum([i[1::][0] for i in elements],[])) for key,elements in groupby(sorted(b[0].items()+b[1].items()),lambda t: t[0])]) 
{1: [2, 3, 4], 2: [3], 3: [1]} 
-1

Así es como lo hago en Python 2.7:

combined = {} 
combined.update(d1) 
combined.update(d2) 

Es bueno definir una función de utilidad para haz esto:

def merge(d1, d2): 
    ''' Merge two dictionaries. ''' 
    merged = {} 
    merged.update(d1) 
    merged.update(d2) 
    return merged 
Cuestiones relacionadas