Tengo dos listas:

a = [0, 0, 0, 1, 1, 1, 1, 1, .... 99999]
b = [24, 53, 88, 32, 45, 24, 88, 53, ...... 1]

Quiero fusionar esas dos listas en un diccionario como:

{
    0: [24, 53, 88], 
    1: [32, 45, 24, 88, 53], 
    ...... 
    99999: [1]
}

Una solución podría estar usando el bucle for, que no se ve bien y elegante, como:

d = {}
unique_a = list(set(list_a))
for i in range(len(list_a)):
    if list_a[i] in d.keys:
        d[list_a[i]].append(list_b[i])
    else:
        d[list_a] = [list_b[i]]

Aunque esto funciona, es ineficiente y tomaría demasiado tiempo cuando la lista es extremadamente grande. ¿Quiero saber formas más elegantes de construir un diccionario de este tipo?

¡Gracias de antemano!

19
BigD 1 nov. 2017 a las 01:07

7 respuestas

La mejor respuesta

Puede usar un defaultdict:

from collections import defaultdict
d = defaultdict(list)
list_a = [0, 0, 0, 1, 1, 1, 1, 1, 9999]
list_b = [24, 53, 88, 32, 45, 24, 88, 53, 1]
for a, b in zip(list_a, list_b):
   d[a].append(b)

print(dict(d))

Salida:

{0: [24, 53, 88], 1: [32, 45, 24, 88, 53], 9999: [1]}
33
Ajax1234 1 nov. 2017 a las 10:32

Tal vez pierda el punto, pero al menos intentaré ayudar. Si tiene que hacer listas y quiere ponerlas en el dict, haga lo siguiente

a = [1, 2, 3, 4]
b = [5, 6, 7, 8]
lists = [a, b] # or directly -> lists = [ [1, 2, 3, 4], [5, 6, 7, 8] ]
new_dict = {}
for idx, sublist in enumerate([a, b]): # or enumerate(lists)
    new_dict[idx] = sublist

Espero que ayuda

2
Giorgi Jambazishvili 31 oct. 2017 a las 22:12

Puede hacer esto con una comprensión dict:

list_a = [0, 0, 0, 1, 1, 1, 1, 1]
list_b = [24, 53, 88, 32, 45, 24, 88, 53]
my_dict = {key: [] for key in set(a)}  # my_dict = {0: [], 1: []}
for a, b in zip(list_a, list_b):
    my_dict[a].append(b)
# {0: [24, 53, 88], 1: [32, 45, 24, 88, 53]}

Por extraño que parezca, no puede hacer que esto funcione con dict.fromkeys(set(list_a), []) ya que esto establecerá el valor de todas las claves igual a la matriz vacía same :

my_dict = dict.fromkeys(set(list_a), [])  # my_dict = {0: [], 1: []}
my_dict[0].append(1)  # my_dict = {0: [1], 1: [1]}
4
Engineero 31 oct. 2017 a las 22:32

Sin estructuras sofisticadas, solo un simple diccionario antiguo.

d = {}
for x, y in zip(a, b):
    d.setdefault(x, []).append(y)
5
cs95 1 nov. 2017 a las 13:24

Alternativa itertools.groupby() solución:

import itertools

a = [0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3]
b = [24, 53, 88, 32, 45, 24, 88, 53, 11, 22, 33, 44, 55, 66, 77]

result = { k: [i[1] for i in g] 
           for k,g in itertools.groupby(sorted(zip(a, b)), key=lambda x:x[0]) }
print(result)

La salida:

{0: [24, 53, 88], 1: [24, 32, 45, 53, 88], 2: [11, 22, 33, 44, 55, 66], 3: [77]}
14
RomanPerekhrest 1 nov. 2017 a las 08:27

O haga la comprensión del diccionario de antemano, luego, dado que todas las claves están allí con valores de listas vacías, repita a través de zip de las dos listas, luego agregue el valor de la segunda lista al valor de la primera lista del nombre de la clave del diccionario, sin necesidad de intentarlo -excepto la cláusula (o las declaraciones if), para ver si la clave existe o no, debido a la comprensión previa del diccionario:

d={k:[] for k in l}
for x,y in zip(l,l2):
   d[x].append(y)

Ahora:

print(d)

Es:

{0: [24, 53, 88], 1: [32, 45, 24, 88, 53], 9999: [1]}
0
U10-Forward 6 nov. 2018 a las 04:17

Una solución pandas:

Configuración:

import pandas as pd

a = [0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 4, 4]

b = pd.np.random.randint(0, 100, len(a)).tolist()

>>> b
Out[]: [28, 68, 71, 25, 25, 79, 30, 50, 17, 1, 35, 23, 52, 87, 21]


df = pd.DataFrame(columns=['Group', 'Value'], data=list(zip(a, b)))  # Create a dataframe

>>> df
Out[]:
    Group  Value
0       0     28
1       0     68
2       0     71
3       1     25
4       1     25
5       1     79
6       1     30
7       1     50
8       2     17
9       2      1
10      2     35
11      3     23
12      4     52
13      4     87
14      4     21

Solución:

>>> df.groupby('Group').Value.apply(list).to_dict()
Out[]:
{0: [28, 68, 71],
 1: [25, 25, 79, 30, 50],
 2: [17, 1, 35],
 3: [23],
 4: [52, 87, 21]}

Tutorial:

  1. crear un pd.DataFrame de las listas de entrada, a se llama Group y b se llama Value
  2. df.groupby('Group') crea grupos basados en a
  3. .Value.apply(list) obtiene los valores para cada grupo y lo envía a list
  4. .to_dict() convierte el DataFrame resultante en dict

Sincronización:

Para tener una idea de los tiempos para un conjunto de prueba de 1,000,000 de valores en 100,000 grupos:

a = sorted(np.random.randint(0, 100000, 1000000).tolist())
b = pd.np.random.randint(0, 100, len(a)).tolist()
df = pd.DataFrame(columns=['Group', 'Value'], data=list(zip(a, b)))

>>> df.shape
Out[]: (1000000, 2)

%timeit df.groupby('Group').Value.apply(list).to_dict()
4.13 s ± 9.29 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Pero para ser sincero, es probable que sea menos eficiente que itertools.groupby sugerido por @RomanPerekhrest, o defaultdict sugerido por @ Ajax1234.

4
FabienP 31 oct. 2017 a las 23:11