Watarap
Watarap

Reputation: 307

Creating dictionary from list in Python - dict key omits Identical items in the list

While creating a dictionary from the list, the keys of the dictionary neglects the identical items in the List and stores the last item as the key.

For example in this:

lst1 = [["Apple",20.00,"Swiss"],
    ["Banana",5.00,"Brazil"],
    ["Strawberry",25.00,"Swiss"],
    ["Pear",12.00,"Greece"],
    ["Mango",3.00,"Peru"],
    ["Avacado",7.00,"Peru"]]

my_dict = {val[2]:val[:2] for val in lst1}

print (my_dict)

Prints this

{'Swiss': ['Strawberry', 25.0], 'Brazil': ['Banana', 5.0], 'Greece': ['Pear', 12.0], 'Peru': ['Avacado', 7.0]}

As far as I understand it does so because the keys can't be identical, then why doesn't it group the values of identical keys in to one list. Like this

{
    'Swiss': [["Apple",20.00],['Strawberry', 25.0]],
    'Brazil': ['Banana', 5.0],
    'Greece': ['Pear', 12.0],
    'Peru': [["Mango",3.00],['Avacado', 7.0]]
}

Is there any way I could do this in pure Python?

Upvotes: 2

Views: 65

Answers (3)

Joe Iddon
Joe Iddon

Reputation: 20414

As far as I am aware, this can't be done in a comprehension, but you can use setdefault to make every 2nd element of each list in lst1 a key in a dictionary which you can then immediately append the slice up to it (as you were doing). The neatness of setdefault is that we can append to a key if it is already there, or create that key and then append if it is not. Both actions being done without an if-statement.

d = {}
for l in lst1:
    d.setdefault(l[2], []).append(l[:2])

giving:

{'Brazil': [['Banana', 5.0]],
 'Greece': [['Pear', 12.0]],
 'Swiss': [['Apple', 20.0], ['Strawberry', 25.0]],
 'Peru': [['Mango', 3.0], ['Avacado', 7.0]]}

Upvotes: 3

Martijn Pieters
Martijn Pieters

Reputation: 1121584

You can't use a dictionary comprehension for this, that can't know about preceding keys already being present.

You'll have to use a straight-up loop. Add all values to a list, not just the repeating ones. Don't mix structures here, that'll only create more headaches later on. If you don't you'll have to detect if you have a nested list or a flat list with one fruit and price later on.

You can use a regular dictionary:

my_dict = {}
for fruit, price, origin in lst1:
    my_dict.setdefault(origin, []).append([fruit, price])

The dict.setdefault() call adds an empty list to the dictionary if the key (the first argument) is missing. It then returns the value for the given key (which could be an already existing list or the new empty list). The line then call list.append() to add the fruit and price.

Or you can use a collections.defaultdict() object to create the empty lists when a key is missing:

from collections import defaultdict

my_dict = defaultdict(list)
for fruit, price, origin in lst1:
    my_dict[origin].append([fruit, price])

Code using a defaultdict is a little more concise, but the downside is that this object will now continue to produce empty lists for missing keys, even when you perhaps didn't intend to due to a bug in your code.

Both produce the desired result:

>>> my_dict = {}
>>> for fruit, price, origin in lst1:
...     my_dict.setdefault(origin, []).append([fruit, price])
...
>>> my_dict
{'Swiss': [['Apple', 20.0], ['Strawberry', 25.0]], 'Brazil': [['Banana', 5.0]], 'Greece': [['Pear', 12.0]], 'Peru': [['Mango', 3.0], ['Avacado', 7.0]]}
>>> from collections import defaultdict
>>> my_dict = defaultdict(list)
>>> for fruit, price, origin in lst1:
...     my_dict[origin].append([fruit, price])
...
>>> my_dict
defaultdict(<class 'list'>, {'Swiss': [['Apple', 20.0], ['Strawberry', 25.0]], 'Brazil': [['Banana', 5.0]], 'Greece': [['Pear', 12.0]], 'Peru': [['Mango', 3.0], ['Avacado', 7.0]]})

Upvotes: 4

Jean-Fran&#231;ois Fabre
Jean-Fran&#231;ois Fabre

Reputation: 140168

Those kind of "accumulation" problems cannot be done simply with list comprehensions (or with ugly side effects which impair readability).

You want collections.defaultdict(list) to create a list of couples as values, and country as key:

lst1 = [["Apple",20.00,"Swiss"],
    ["Banana",5.00,"Brazil"],
    ["Strawberry",25.00,"Swiss"],
    ["Pear",12.00,"Greece"],
    ["Mango",3.00,"Peru"],
    ["Avacado",7.00,"Peru"]]

result = collections.defaultdict(list)

for fruit,price,country in lst1:
    result[country].append([fruit,price])

print(dict(result))  # convert to dict for a cleaner representation when printing

result:

{'Swiss': [['Apple', 20.0], ['Strawberry', 25.0]], 'Brazil': [['Banana', 5.0]], 'Greece': [['Pear', 12.0]], 'Peru': [['Mango', 3.0], ['Avacado', 7.0]]}

Upvotes: 3

Related Questions