2012-07-25 25 views
7

Digamos que tengo los siguientes dos listas de tuplasPython manera más fácil de Suma Lista intersección de la lista de tuplas

myList = [(1, 7), (3, 3), (5, 9)] 
otherList = [(2, 4), (3, 5), (5, 2), (7, 8)] 

returns => [(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)] 

me gustaría diseñar una operación de fusión que combina estas dos listas mediante la comprobación de las intersecciones en el primer elemento de la tupla, si hay intersecciones, agregue los segundos elementos de cada tupla en cuestión (combine los dos). Después de la operación, me gustaría ordenar en función del primer elemento.

También estoy fijando esto porque creo que es un problema bastante común que tiene una solución obvia, pero siento que podría haber soluciones muy Pythonic a esta pregunta;)

Respuesta

14

uso de un diccionario para el resultado:

result = {} 
for k, v in my_list + other_list: 
    result[k] = result.get(k, 0) + v 

Si quiere una lista de tuplas, puede obtenerla a través del result.items(). La lista resultante estará en orden arbitrario, pero por supuesto puede ordenarla si lo desea.

(. Tenga en cuenta que el nuevo nombre de sus listas para ajustarse a las convenciones de estilo de Python)

+0

Realmente limpio. Buena solución! –

+0

Tenga en cuenta que 'result.items()' devolverá un objeto 'dict_items' en Python 3. Por supuesto, siempre puede hacer' list (result.items()) '. – kamek

1

un método que utiliza itertools:

>>> myList = [(1, 7), (3, 3), (5, 9)] 
>>> otherList = [(2, 4), (3, 5), (5, 2), (7, 8)] 

>>> import itertools 
>>> merged = [] 
>>> for k, g in itertools.groupby(sorted(myList + otherList), lambda e: e[0]): 
... merged.append((k, sum(e[1] for e in g))) 
... 
>>> merged 
[(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)] 

Este primer concatena las dos listas y la ordena. itertools.groupby devuelve los elementos de la lista fusionada, agrupados por el primer elemento de la tupla, por lo que solo los resume y los coloca en la lista fusionada.

4

Uso defaultdict:

from collections import defaultdict 
results_dict = defaultdict(int) 
results_dict.update(my_list) 
for a, b in other_list: 
    results_dict[a] += b 
results = sorted(results_dict.items()) 

Nota: al ordenar secuencias, sorted ordena por el primer elemento de la secuencia. Si los primeros elementos son iguales, entonces compara el segundo elemento. Usted puede dar sorted una función para ordenar por, utilizando la palabra clave key argumento:

results = sorted(results_dict.items(), key=lambda x: x[1]) #sort by the 2nd item 

o

results = sorted(results_dict.items(), key=lambda x: abs(x[0])) #sort by absolute value 
+0

(+1) No sé cómo todo este tiempo no me di cuenta de que 'dict.update' acepta una secuencia igual que el constructor dict. Además, es trivial ordenar el primer elemento de la tupla según lo solicitado por el OP ('results = sorted (results_dict.items())') – mgilson

+0

@mgilson: ¡Gracias! Me perdí la parte sobre un resultado ordenado. Editaré –

+0

@mgilson: Aparentemente 'update()' aceptando iterables se introdujo en 2.4. –

0
>>> [(k, sum(v for x,v in myList + otherList if k == x)) for k in dict(myList + otherList).keys()] 
[(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)] 
>>> 

testados para Python2.7 y 3,2
dict(myList + otherList).keys() devuelve un iterable que contenga una conjunto de las claves para las listas unidas
sum(...) toma 'k' para volver a pasar por la lista unida y sumar los elementos de la tupla 'v' donde k == x

... pero el bucle adicional agrega una sobrecarga de procesamiento. Usar un diccionario explícito como lo propone Sven Marnach lo evita.

Cuestiones relacionadas