mad_python
mad_python

Reputation: 43

How to group a bunch of lists by a key to a single dictionary in Python

I have a bunch of lists that contain elements that are related to each other and I want to convert them to a single dictionary with lists as values:

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

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

How could I do that?

Upvotes: 3

Views: 715

Answers (7)

Danil Speransky
Danil Speransky

Reputation: 30453

Simple approach:

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

Using 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']})

Using groupby from 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']}

Using reduce from 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']}

Upvotes: 5

Ajax1234
Ajax1234

Reputation: 71451

You can merely iterate over a nested list of original data and use a OrderedDict to retain the order of entry:

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]

Output:

OrderedDict([('animal', ['cat', 'dog']), ('bird', ['crow'])])

Upvotes: 1

Alexander
Alexander

Reputation: 109528

Given that your lists consists of pairs where the first item is the value and the second is the key, you can use a defaultdict constructed with lists and then just append the results.

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

If you don't want keys with only one element to be in a list (e.g. 'bird': ['crow'] should be 'bird': 'crow'), then just convert the result:

new_result = {k: v[0] if len(v) == 1 else v for k, v in dd.iteritems()}
>>> new_result
{'animal': ['cat', 'dog'], 'bird': 'crow'}

Upvotes: 1

Brad Solomon
Brad Solomon

Reputation: 40878

The other answers using defaultdict don't exactly match your intended output. Here's a version without defaultdict that does.

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

Upvotes: 1

Michael
Michael

Reputation: 1180

If you have tuple of lists or list of lists following coed will be suitable. If you have defined variables with lists, you can simply add all lists into one variable firstly and then process it with algorithm written below.

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)

Upvotes: 1

James
James

Reputation: 36598

You can use the defaultdict from the collections module. It is part of the standard library and operates the same as a dictionary with the exception that if a new key is passed, it will create a new value (a list in this case) automatically

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

Upvotes: 1

Cuber
Cuber

Reputation: 713

If you have a list of lists that you want to convert, you can do this:

dict1 = {}
for li in lists:

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

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

Note that this will produce dict1={'animal':['cat','dog'],'bird':['crow']} instead of dict1={'animal':['cat','dog'],'bird':'crow'}, which is what you have in the question.

Upvotes: 1

Related Questions