Подтвердить что ты не робот

Как объединить два списка в словарь без использования вложенных циклов

У меня есть два списка:

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

Я хочу объединить эти два списка в словарь вроде:

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

В решении может использоваться цикл for, который выглядит не очень хорошо и элегантно, например:

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

Хотя это действительно работает, оно неэффективно и занимает слишком много времени, когда список чрезвычайно велик. Я хочу узнать более элегантные способы построения такого словаря?

Спасибо заранее!

4b9b3361

Ответ 1

Вы можете использовать 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))

Вывод:

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

Ответ 2

Альтернативный itertools.groupby() решение:

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)

Выход:

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

Ответ 3

Нет фантазийных структур, просто простого словаря.

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

Ответ 4

Вы можете сделать это с пониманием 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]}

Как ни странно, вы не можете сделать эту работу с помощью dict.fromkeys(set(list_a), []), так как это установит значение всех ключей, равных одному и тому же пустым массивам:

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

Ответ 5

A pandas решение:

Настройка:

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

Решение:

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

Пошаговое руководство:

  • создайте pd.DataFrame из входных списков, a называется Group и b называется Value
  • df.groupby('Group') создает группы на основе a
  • .Value.apply(list) получает значения для каждой группы и передает ее в list
  • .to_dict() преобразует полученный DataFrame в dict

Сроки:

Чтобы получить представление о таймингах для тестового набора из 1000 000 значений в 100 000 групп:

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)

Но, честно говоря, он, вероятно, менее эффективен, чем itertools.groupby, предложенный @RomanPerekhrest, или defaultdict, предложенный @Ajax1234.

Ответ 6

Возможно, я скучаю по этому пункту, но по крайней мере я постараюсь помочь. Если у вас есть списки и вы хотите поместить их в dict, выполните следующие

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

надеюсь, что это поможет

Ответ 7

Было предложено использовать dict (zip (list1, list2))