web-dev-qa-db-fra.com

Comment fusionner deux listes dans un dictionnaire sans utiliser la boucle for imbriquée

J'ai deux listes:

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

Je veux fusionner ces deux listes dans un dictionnaire comme: 

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

Une solution pourrait utiliser la boucle for, qui n'a pas l'air bonne et élégante, comme:

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

Bien que cela fonctionne, il est inefficace et prendrait trop de temps lorsque la liste est extrêmement longue. Je veux savoir des façons plus élégantes de construire un tel dictionnaire? 

Merci d'avance!

18
BigD

Vous pouvez utiliser 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))

Sortie:

{0: [24, 53, 88], 1: [32, 45, 24, 88, 53], 9999: [1]}
30
Ajax1234

Alternative itertools.groupby() solution:

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)

Le résultat:

{0: [24, 53, 88], 1: [24, 32, 45, 53, 88], 2: [11, 22, 33, 44, 55, 66], 3: [77]}
13
RomanPerekhrest

Pas de structures fantaisistes, juste un vieux dictionnaire.

d = {}
for x, y in Zip(a, b):
    d.setdefault(x, []).append(y)
5
coldspeed

Vous pouvez le faire avec une compréhension dictée:

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

Curieusement, vous ne pouvez pas sembler fonctionner avec dict.fromkeys(set(list_a), []) car cela va définir la valeur de toutes les clés égale au tableau same empty:

my_dict = dict.fromkeys(set(list_a), [])  # my_dict = {0: [], 1: []}
my_dict[0].append(1)  # my_dict = {0: [1], 1: [1]}
4
Engineero

Une solution pandas:

Installer:

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

Solution:

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

Procédure pas à pas:

  1. créer un pd.DataFrame à partir des listes d'entrées, a est appelé Group et b appelé Value
  2. df.groupby('Group') crée des groupes basés sur a
  3. .Value.apply(list) récupère les valeurs de chaque groupe et le transforme en list
  4. .to_dict() convertit la DataFrame résultante en dict

Timing:

Pour avoir une idée des temps pour un ensemble de test de 1 000 000 de valeurs sur 100 000 groupes:

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)

Mais pour être honnête, il est probablement moins efficace que itertools.groupby suggéré par @RomanPerekhrest ou defaultdict suggéré par @ Ajax1234.

3
FabienP

Peut-être que je manque le point, mais au moins je vais essayer d'aider. Si vous avez des listes et que vous voulez les mettre dans le dict, procédez comme suit:

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

j'espère que ça aide

2

Ou bien faites la compréhension du dictionnaire auparavant, puis puisque toutes les clés sont là avec des valeurs de listes vides, parcourez la variable Zip des deux listes, puis ajoutez la valeur de la deuxième liste à la valeur de la première liste du dictionnaire, pas besoin de clause try-except ( ou if)), pour voir si la clé existe ou non, à cause de la compréhension préalable du dictionnaire:

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

À présent:

print(d)

Est:

{0: [24, 53, 88], 1: [32, 45, 24, 88, 53], 9999: [1]}
0
U9-Forward