У меня есть несколько списков, которые содержат элементы, которые связаны друг с другом, и я хочу преобразовать их в один словарь со списками в качестве значений:

list1 = ['cat', 'animal']
list2 = ['dog', 'animal']
list3 = ['crow', 'bird']

result = {'animal': ['cat', 'dog'], 'bird': 'crow'}

Как я мог это сделать?

2
mad_python 27 Авг 2017 в 22:18

7 ответов

Лучший ответ

Простой подход .

data = [['cat', 'animal'], ['dog', 'animal'], ['crow', 'bird']]

result = {}

for value, key in data:
    result[key] = result.get(key, []) + [value]

result #=> {'bird': ['crow'], 'animal': ['cat', 'dog']}

Использование defaultdict:

from collections import defaultdict

data = [['cat', 'animal'], ['dog', 'animal'], ['crow', 'bird']]

result = defaultdict(list)

for value, key in data:
    result[key].append(value)

result #=> defaultdict(<class 'list'>, {'animal': ['cat', 'dog'], 'bird': ['crow']})

Использование groupby из itertools:

from itertools import groupby

data = [['cat', 'animal'], ['dog', 'animal'], ['crow', 'bird']]

{k: [x[0] for x in g] for k, g in groupby(data, lambda x: x[1])}
#=> {'bird': ['crow'], 'animal': ['cat', 'dog']}

Использование reduce из functools:

from functools import reduce

data = [['cat', 'animal'], ['dog', 'animal'], ['crow', 'bird']]

reduce(lambda a, e: dict(a, **{e[1]: a.get(e[1], []) + [e[0]]}), data, {})
#=> {'bird': ['crow'], 'animal': ['cat', 'dog']}
2
Danil Speransky 27 Авг 2017 в 20:00

Поскольку ваши списки состоят из пар, в которых первый элемент является значением, а второй - ключом, вы можете использовать defaultdict создается со списками, а затем просто добавляет результаты.

from collections import defaultdict

dd = defaultdict(list)
my_lists = [list1, list2, list3]
for my_paired_list in my_lists:
    v, k = my_paired_list
    dd[k].append(v)
>>> dict(dd)
{'animal': ['cat', 'dog'], 'bird': ['crow']}

Если вы не хотите, чтобы ключи с одним элементом были в списке (например, 'bird': ['crow'] должно быть 'bird': 'crow'), просто преобразуйте результат:

new_result = {k: v[0] if len(v) == 1 else v for k, v in dd.iteritems()}
>>> new_result
{'animal': ['cat', 'dog'], 'bird': 'crow'}
1
Alexander 27 Авг 2017 в 19:34

Если у вас есть список списков, которые вы хотите преобразовать, вы можете сделать это:

dict1 = {}
for li in lists:

   if(li[1] not in dict1):
      dict1[li[1]] = []

   dict1[li1].append(li[0])

Обратите внимание, что это даст dict1={'animal':['cat','dog'],'bird':['crow']} вместо dict1={'animal':['cat','dog'],'bird':'crow'}, что и есть в вопросе.

1
Cuber 27 Авг 2017 в 19:22

Вы можете использовать defaultdict из модуля collections. Он является частью стандартной библиотеки и работает так же, как словарь, за исключением того, что, если передан новый ключ, он автоматически создаст новое значение (в данном случае список)

list1=['cat','animal']
list2=['dog','animal']
list3=['crow','bird']


from collections import defaultdict

# create a new dictionary where an unknown key will automatically
# add the key to the dictionary with a empty list as the value
d = defaultdict(list)

# iterate over your lists, updating the dictionary
for value, key in (list1, list2, list3):
    d[key].append(value)

d
# returns:
defaultdict(list, {'animal': ['cat', 'dog'], 'bird': ['crow']})
1
James 27 Авг 2017 в 19:22

Другие ответы, использующие defaultdict, не совсем соответствуют предполагаемому результату. Вот версия без defaultdict, которая делает.

list1=['cat','animal']
list2=['dog','animal']
list3=['crow','bird']

dict1 = {}
for v, k in (list1, list2, list3):
    if k in dict1:
        # If the value already exists (as string), convert it to list
        # and append the new value
        dict1[k] = [dict1[k]]
        dict1[k].append(v)
    else:
        # Otherwise, we just want a string, not list
        dict1[k] = v

print(dict1)
{'animal': ['cat', 'dog'], 'bird': 'crow'}
1
Brad Solomon 27 Авг 2017 в 19:31

Вы можете просто перебрать вложенный список исходных данных и использовать OrderedDict, чтобы сохранить порядок ввода:

from collections import OrderedDict

data = [
  ['cat', 'animal'],
  ['dog', 'animal'],
  ['crow', 'bird']
]

d = OrderedDict()

for name, type in data:
   if type in d:
      d[type].append(name)
   else:
      d[type] = [name]

Выход:

OrderedDict([('animal', ['cat', 'dog']), ('bird', ['crow'])])
1
Ajax1234 27 Авг 2017 в 19:43

Если у вас есть кортеж списков или список списков, вам подойдет следующий код. Если вы определили переменные со списками, вы можете сначала просто добавить все списки в одну переменную, а затем обработать ее с помощью алгоритма, описанного ниже.

lists = ['cat','animal'],['dog','animal'],['crow','bird']
results = {}

for list in lists:
    if list[1] in results:
        results[list[1]].append(list[0])
        print('bingo')
    else:
        results[list[1]] = [list[0]]

print(results)
1
Michael 27 Авг 2017 в 19:29