una - python quitar duplicados
encontrar duplicados en una lista de listas (7)
Estoy usando Python 2.7 y estoy tratando de quitar la duplicación de una lista de listas y combinar los valores de los duplicados.
En este momento tengo:
original_list = [[''a'', 1], [''b'', 1], [''a'', 1], [''b'', 1], [''b'', 2], [''c'', 2], [''b'', 3]]
Quiero hacer coincidir el primer elemento de cada lista anidada y luego agregar los valores del segundo elemento. Quiero terminar con esto (el orden de la lista final no importa):
ideal_output = [[''a'', 2], [''b'', 7], [''c'', 2]]
Hasta ahora tengo un código que me encontrará los valores duplicados en función del primer elemento de cada lista anidada:
for item in original_list:
matches = -1
for x in original_list:
if (item[0] == x[0]):
matches += 1
if matches >= 1:
if item[0] not in duplicates_list:
duplicates_list.append(item[0])
Desde aquí necesito buscar todos los elementos de la lista de duplicados que están en la lista original y sumar los valores, pero no estoy seguro de cuál es la mejor manera de hacerlo.
SOLUCIÓN
Usar collections.Counter
. collections.Counter
:
from collections import Counter
original_list = [[''a'', 1], [''b'', 1], [''a'', 1], [''b'', 1], [''b'', 2], [''c'', 2], [''b'', 3]]
result = Counter()
for k, v in original_list:
result.update({k:v})
map(list, result.items())
# [[''a'', 2], [''c'', 2], [''b'', 7]]
RECOMENDACIONES
Entonces, muchas respuestas, puntos de vista y votaciones ascendentes. Incluso obtuve mi primera Nice answer
de la nada (en los últimos 2 días hice un montón de respuestas por valor de más investigación y esfuerzos). En vista de esto, decidí hacer al menos un rendimiento de soluciones de investigación y prueba con un simple script escrito desde cero. No incluya el código directamente en la respuesta por el tamaño.
Cada función lleva el nombre de su autor y se puede encontrar fácilmente en cuestión. La solución de itertools.groupby
ahora es igual a una de Mark Reed y se evalúa en su forma original, thefourtheye2 establece para la solución basada en itertools.groupby
.
Cada uno se probó varias veces (muestras), cada muestra a su vez invocó varias iteraciones de funciones. Evalué min, max y desviación estándar para muestras veces.
Aquí vamos, haciendo una prueba de sondeo por 10 veces.
testing: thefourtheye, kroolik2, void, kroolik, alko, reed, visser
10 samples
10 iterations each
author min avg max stddev
reed 0.00000 0.00000 0.00000 0.00000
visser 0.00000 0.00150 0.01500 0.00450
thefourtheye 0.00000 0.00160 0.01600 0.00480
thefourtheye2 0.00000 0.00310 0.01600 0.00620
alko 0.00000 0.00630 0.01600 0.00772
void 0.01500 0.01540 0.01600 0.00049
kroolik2 0.04700 0.06430 0.07800 0.00831
kroolik 0.32800 0.34380 0.37500 0.01716
Observe las dos filas inferiores: en este punto, las soluciones de kroolik se descalificaron, ya que con ellas se realizarán iteraciones razonables de muestras * durante horas. Aquí van las pruebas finales. Yo manualmente agregué el número de votos a favor de ouptut:
testing: thefourtheye, kroolik2, void, kroolik, alko, reed, visser
100 samples
1000 iterations each
author upvotes min avg max stddev
reed [20] 0.06200 0.08174 0.15600 0.01841
thefourtheye [5] 0.06200 0.09971 0.20300 0.01911
visser [6] 0.10900 0.12392 0.23500 0.02263
thefourtheye2 0.25000 0.29674 0.89000 0.07183
alko [11] 0.56200 0.62309 1.04700 0.08438
void [3] 1.50000 1.65480 2.39100 0.18721
kroolik [14] [DSQ]
Muchas buenas respuestas, pero todas usan bastante más código del que usaría para esto, así que aquí está mi opinión, por lo que vale:
totals = {}
for k,v in original_list:
totals[k] = totals.get(k,0) + v
# totals = {''a'': 2, ''c'': 2, ''b'': 7}
Una vez que tenga un dict como ese, a partir de cualquiera de estas respuestas, puede usar items
para obtener una lista de tuplas:
totals.items()
# => [(''a'', 2), (''c'', 2), (''b'', 7)]
Y una list
mapas a través de las tuplas para obtener una lista de listas:
map(list, totals.items())
# => [[''a'', 2], [''c'', 2], [''b'', 7]]
Y ordena si los quieres en orden:
sorted(map(list, totals.items()))
# => [[''a'', 2], [''b'', 7], [''c'', 2]]
Puede ser que puedas probar esto también,
>>> x = [[1,1],[2,2],[1,1],[2,2],[3,3],[4,4],[4,4]]
>>> z = []
>>> for i in x:
>>> if i not in z:
>>> z.append(i)
>>>
>>> z
[[1, 1], [2, 2], [3, 3], [4, 4]]
Puede usar collections.defaultdict
:
original_list = [[''a'', 1], [''b'', 1], [''a'', 1], [''b'', 1], [''b'', 2], [''c'', 2], [''b'', 3]]
import collections
data = collections.defaultdict(list)
for item in original_list:
data[item[0]].append(item[1])
output = {key: sum(values) for key, values in data.items()}
print output
# gives: {''a'': 2, ''c'': 2, ''b'': 7}
Sé que es feo, pero me estaba divirtiendo al tratar de implementarlo en un trazador de líneas 1:
map(list, set(([(x[0], sum([i[1] for i in original_list if i[0]==x[0]])) for x in original_list])))
salida:
[[''a'', 2], [''b'', 7], [''c'', 2]]
Si la orden no importa, puede usar esto
original_list = [[''a'', 1], [''b'', 1], [''a'', 1], [''b'', 1], [''b'', 2], [''c'', 2], [''b'', 3]]
myDict = {}
for first, second in original_list:
myDict[first] = myDict.get(first, 0) + second
result = [[key, value] for key, value in myDict.items()]
print result
O puede usar groupby y el código se convierte en un oneliner
original_list = [[''a'', 1], [''b'', 1], [''a'', 1], [''b'', 1], [''b'', 2], [''c'', 2], [''b'', 3]]
from itertools import groupby
print [[key, sum(item[1] for item in list(group))]
for key, group in groupby(sorted(original_list), lambda x:x[0])]
Salida
[[''a'', 2], [''b'', 7], [''c'', 2]]
>>> from collections import Counter
>>> lst = [[''a'', 1], [''b'', 1], [''a'', 1], [''b'', 1], [''b'', 2], [''c'', 2], [''b'', 3]]
>>> c = Counter(x for x, c in lst for _ in xrange(c))
Counter({''b'': 7, ''a'': 2, ''c'': 2})
>>> map(list, c.iteritems())
[[''a'', 2], [''c'', 2], [''b'', 7]]
O alternativamente, sin repetir cada elemento (a, b)
b veces (@hcwhsa):
>>> from collections import Counter
>>> lst = [[''a'', 1], [''b'', 1], [''a'', 1], [''b'', 1], [''b'', 2], [''c'', 2], [''b'', 3]]
>>> c = sum((Counter(**{k:v}) for k, v in lst), Counter())
Counter({''b'': 7, ''a'': 2, ''c'': 2})
>>> map(list, c.iteritems())
[[''a'', 2], [''c'', 2], [''b'', 7]]