Adding Multiple Values to Single Key in Python Dictionary Comprehension

Question:

I wanted to learn how to use dictionary comprehension and decided to use one for the previously solved task. I need to assign multiple values to the same key. I was wondering if there’s a better way to achieve what I’m trying to do than with the code I’ve written so far.

graph = {(x1,y1): [(c,d) for a,b,c,d in data if a == x1 and b == y1] for x1 ,y1, x2, y2 in data}

For example I have this:

data = {(1,2,1,5),(1,2,7,2),(1,5,4,7),(4,7,7,5)}

The first two values should create a key and the remaining two should be added as a value of a key.
With the given example I would like to return:

{(1, 2): [(1, 5), (7, 2)], (1, 5): [(4, 7)], (4, 7): [(7, 5)]}

Is there an easier way to do it than iterate through the entire data just to find the matching values?

Asked By: Gabbek

||

Answers:

Your code is neat but the time complexity is O(n^2), which can be reduced to O(n).

data = {(1,2,1,5),(1,2,7,2),(1,5,4,7),(4,7,7,5)}
result = dict()
for item in data:
    key = (item[0],item[1])
    value = result.setdefault(key,[])
    value.append((item[2],item[3]))
    result[key] = value
print result

In my opinion, using a for loop can make codes more comprehensive

Answered By: Hooting

I don’t know if it is the best answer but I would do something like that :

m_dict = {}
for val in data:
    key = (val[0],val[1])
    if key in m_dict:
        m_dict[key].append((val[2],val[3]))
    else:
        m_dict[key] = [(val[2],val[3])]

Or more concisely using setdefault:

m_dict = {}
for val in data:
    key = (val[0],val[1])
    obj = m_dict.setdefault(key,[])
    obj.append((val[2],val[3]))
Answered By: Mathiou

Using this dict comprehension isn’t an efficient way here. It loops over the same input data repeatedly.

It’s more Pythonic to just use a simple for loop, iterating the data only once:

from collections import defaultdict

data = {(1,2,1,5),(1,2,7,2),(1,5,4,7),(4,7,7,5)}
output = defaultdict(list)

for a, b, c, d in data:
    output[a, b].append((c, d))
Answered By: wim

In this instance, I would use itertools.groupby. For your example:

dict(groupby(data, lambda t: (t[0], t[1])))

This will produce a dict with the keys equal to (1, 2), (1, 5), and (4, 7) and the values consisting of (1, 2, 1, 5), (1, 2, 7, 2)... which should be sufficient for most uses. You can also post-process the grouped list, if need be.


As noted in the comments below, groupby requires sorted data. As such, you will need to sort before grouping and will probably want to cast the iterator to a list:

first_two = lambda tup: (tup[0], tup[1])
groups = groupby(sorted(data, key=first_two), first_two)
target = {k: list(g) for k, g in groups}
Answered By: asthasr
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.