'Dictionary with a list as value

I have a list of tuples:

res=[(0, 0, 255, 0, 0),(1, 0, 255, 0, 0),(0, 1, 255, 0, 0),(1, 1, 255, 0, 0),
(4, 4, 0, 255, 0),(5, 4, 0, 255, 0),(4, 5, 0, 255, 0),(5, 5, 0, 255, 0)]

This is my idea:

keys = [l[2:] for l in res]
values = [l[:2] for l in res]
d=dict(zip(keys, values))

and this is my output:

{(255, 0, 0): (1, 1), (0, 255, 0): (5, 5)}

My output is wrong, I need this one:

{(255, 0, 0): [(0, 0),(1,0),(0,1),(1,1)], 
(0, 255, 0): [(4,4),(5,4),(4,5),(5,5)]}

Any ideas?



Solution 1:[1]

There are much more elegant solutions to this problem, but the point of the exercise is (likely) for you to practice logic and control flow, so I'll show a more beginner-appropriate solution:

output = {}
for entry in res:
    key, value = entry[2:], entry[:2]
    if key not in output:
        output[key] = []
    output[key].append(value)

As has been mentioned though, collections.defaultdict(list) is the prime candidate for a problem like this.

Solution 2:[2]

Using collections.defaultdict:

from collections import defaultdict 

out = defaultdict(list)

for t in res:
    out[t[2:]].append(t[:2])

dict(out)

Or with a classical dictionary:

out = {}

for t in res:
    k = t[2:]
    if k not in out:
        out[k] = []
    out[k].append(t[:2])

Output:

{(255, 0, 0): [(0, 0), (1, 0), (0, 1), (1, 1)],
 (0, 255, 0): [(4, 4), (5, 4), (4, 5), (5, 5)]}

Solution 3:[3]

You can use a dictionary with .setdefault() to accumulate the results, using slicing to generate the appropriate keys and values.

ans = {}

for entry in res:
    ans.setdefault(entry[2:], []).append(entry[:2])
    
print(ans)

This outputs:

{
 (255, 0, 0): [(0, 0), (1, 0), (0, 1), (1, 1)],
 (0, 255, 0): [(4, 4), (5, 4), (4, 5), (5, 5)]
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ddejohn
Solution 2 Sunderam Dubey
Solution 3 Sunderam Dubey