Reputation: 17651
I have an algorithmic problem using a Python3.x dictionary of lists, though perhaps another data structure is more appropriate.
Let's say I have the following Python dictionary:
dict1 = {1:[4, 12, 22], 2:[4, 5, 13, 23], 3:[7, 15, 25]}
The key 1
associate with the value [4, 12, 22]
signifies that 1 is "associated with" 4. 1 is also associated with 12, and 1 associated with 22. Also, 2 is associated with 4, 2 is associated with 5, 2 associated with 13, and 1 associated with 23, etc.
My question is, for this small example, how do I "unfold" this dictionary such that each element of the value list encodes this "association"?
That is, the end result should be:
intended_dict = {1:[4, 12, 22], 2:[4, 5, 13, 23], 3:[7, 15, 25],
4:[1, 2], 5:[2], 12:[1], 13:[2], 15:[3], 22:[1], 23:[2], 25:[3]}
because 4 is associated with 1, 4 is associated with 2, 5 is associate with 2, etc.
Is there a method to "unfold" dictionaries like this?
How would this scale to a far larger dictionary with larger lists with millions of integers?
Perhaps another data structure would be more efficient here, especially with far larger lists?
EDIT: Given the size of the actual dictionary I am working with (not the one posted above), the solution should try to be as memory-/performance-efficient as possible.
Upvotes: 1
Views: 1004
Reputation: 8162
You're basically trying to store relations. There's a whole field about this -- they are stored in relational databases, which contain tables. In Python it would be more natural to do this as a list of 2-lists -- or, as your relation is symmetrical and order doesn't matter, a list of 2-sets. An even better solution though is pandas
which is the canonical package for doing tables in Python.
For the time being here's how to turn your original thing into a pandas
object, and then turn that into your fixed thing for including the symmetries.
import pandas as pd
dict1 = {1:[4, 12, 22], 2:[4, 5, 13, 23], 3:[7, 15, 25]}
relations = pd.DataFrame(
[[key, value] for key, values in dict1.items() for value in values]
)
print(relations)
Out:
0 1
0 1 4
1 1 12
2 1 22
3 2 4
4 2 5
5 2 13
6 2 23
7 3 7
8 3 15
9 3 25
result = {
**{key: list(values) for key, values in relations.groupby(0)[1]},
**{key: list(values) for key, values in relations.groupby(1)[0]}
}
print(result)
Out:
{1: [4, 12, 22],
2: [4, 5, 13, 23],
3: [7, 15, 25],
4: [1, 2],
5: [2],
7: [3],
12: [1],
13: [2],
15: [3],
22: [1],
23: [2],
25: [3]}
Upvotes: 1
Reputation: 71620
Simple one liner:
newdict={v:[i for i in dict1.keys() if v in dict1[i]] for k,v in dict1.items() for v in v}
print(newdict)
Output:
{4: [1, 2], 12: [1], 22: [1], 5: [2], 13: [2], 23: [2], 7: [3], 15: [3], 25: [3]}
To merge them:
print({**dict1,**newdict})
Upvotes: 1
Reputation: 3547
One way is using collections.defaultdict
from collections import defaultdict
dict1 = {1:[4, 12, 22], 2:[4, 5, 13, 23], 3:[7, 15, 25]}
d_dict = defaultdict(list)
for k,l in dict1.items():
for v in l:
d_dict[v].append(k)
intended_dict = {**dict1, **d_dict}
print (intended_dict)
#{1: [4, 12, 22], 2: [4, 5, 13, 23], 3: [7, 15, 25], 4: [1, 2], 12: [1], 22: [1], 5: [2], 13: [2], 23: [2], 7: [3], 15: [3], 25: [3]}
Upvotes: 1
Reputation: 107134
The following will do:
intended_dict = dict1.copy()
for k, v in dict1.items():
for i in v:
intended_dict.setdefault(i, []).append(k)
Upvotes: 1