Similarly to this question and this question, I'd like to swap keys and values in a dictionary.
The difference is, my values are lists, not just single values.
Thus, I'd like to turn:
In [120]: swapdict = dict(foo=['a', 'b'], bar=['c', 'd'])
In [121]: swapdict
Out[121]: {'bar': ['c', 'd'], 'foo': ['a', 'b']}
into:
{'a': 'foo', 'b': 'foo', 'c': 'bar', 'd': 'bar'}
Let's assume I'm happy that my values are unique.
You can use a dictionary comprehension and the .items() method.
In []: {k: oldk for oldk, oldv in swapdict.items() for k in oldv}
Out[]: {'a': 'foo', 'b': 'foo', 'c': 'bar', 'd': 'bar'}
Related
with a list like below that has one or more dicts
l = [{'b': 'h', 'c': (1,2)}, {'d': [0, 1], 'e': {'f': 2, 'g': 'i'} } ]
need to extract each key-value pair as an individual dict
Expected output
[{'b': 'h'}, {'c': (1,2)}, {'d': [0, 1]}, {'e': {'f': 2, 'g': 'i'} } ]
I have been trying to do this via list comprehension - the outer comprehension could be something like [ {k,v} for k, v in ?? - need some help in getting the inner comprehension.
I believe this is what you're looking for - except that the order of the elements might be different, but that's to be expected when dealing with dictionaries:
lst = [{'b': 'h', 'c': (1,2)}, {'d': [0, 1], 'e': {'f': 2, 'g': 'i'}}]
[{k: v} for d in lst for k, v in d.items()]
=> [{'c': (1, 2)}, {'b': 'h'}, {'e': {'g': 'i', 'f': 2}}, {'d': [0, 1]}]
This should work:
[{k: v} for i in l for k, v in i.items()]
This question already has answers here:
Combining 2 dictionaries with common key
(5 answers)
Closed 3 years ago.
I am not looking for something like this:
How do I merge two dictionaries in a single expression?
Generic way of updating python dictionary without overwriting the subdictionaries
Python: Dictionary merge by updating but not overwriting if value exists
I am looking for something like this:
input:
d1 = {'a': 'a', 'b': 'b'}
d2 = {'b': 'c', 'c': 'd'}
output:
new_dict = {'a': ['a'], 'b': ['b', 'c'], 'c': ['d']}
I have the following code which works but I am wondering if there is a more efficient method:
First, I create a list "unique_vals", where all the values that are present in both dicts are stored.
From this, a new dictionary is created which stores all the values present in both dictionaries
unique_vals = []
new_dict = {}
for key in list(d1.keys())+list(d2.keys()) :
unique_vals = []
try:
for val in d1[key]:
try:
for val1 in d2[key]:
if(val1 == val) and (val1 not in unique_vals):
unique_vals.append(val)
except:
continue
except:
new_dict[key] = unique_vals
new_dict[key] = unique_vals
Then, for every value in both dictionaries that are not listed in this new dictionary, these values are appended to the new dictionary.
for key in d1.keys():
for val in d1[key]:
if val not in new_dict[key]:
new_dict[key].append(val)
for key in d2.keys():
for val in d2[key]:
if val not in new_dict[key]:
new_dict[key].append(val)
Maybe with a defaultdict?
>>> d1 = {'a': 'a', 'b': 'b'}
>>> d2 = {'b': 'c', 'c': 'd'}
>>> from collections import defaultdict
>>>
>>> merged = defaultdict(list)
>>> dicts = [d1, d2]
>>> for d in dicts:
...: for key, value in d.items():
...: merged[key].append(value)
...:
>>> merged
defaultdict(list, {'a': ['a'], 'b': ['b', 'c'], 'c': ['d']})
This works with any number of dictionaries in the dicts list.
As a function:
def merge_dicts(dicts):
merged = defaultdict(list)
for d in dicts:
for key, value in d.items():
merged[key].append(value)
return merged
Here is a far simpler version:
d1 = {'a': 'a', 'b': 'b'}
d2 = {'b': 'c', 'c': 'd'}
new_dict = {key: [value] for key, value in d1.items()}
for key, value in d2.items():
try:
new_dict[key].append(value)
except:
new_dict[key] = [value]
Output:
{'a': ['a'], 'b': ['b', 'c'], 'c': ['d']}
EDIT: Solution below is for the original question, see other answers or duplicate for updated question.
A one line solution:
def merge_dicts(*dcts):
return {k: [d[k] for d in dcts if k in d] for k in {k for d in dcts for k in d.keys()}}
d1 = {'a': 'a', 'b': 'b'}
d2 = {'b': 'c', 'c': 'd'}
print(merge_dicts(d1, d2))
# {'c': ['d'], 'a': ['a'], 'b': ['b', 'c']}
I have a python dictionary containing some example keys and values:
{'a': ['b'],
'c': ['d'],
'x': ['y'],
'y': ['x'],
'i': ['j','k'],
'j': ['i','k']
'k': ['i','j']}
What letter the key is and which letters are values are irrelevant providing they are shown to have a relationship. I need to be able to remove any 'duplicate' key-value combination so that my dictionary would be displayed as follows.
{'a': ['b'],
'c': ['d'],
'x': ['y'],
'i': ['j','k']}
You can turn each entry to a tuple and use a set to get O(n) time.
d = {'a': ['b'],
'c': ['d'],
'x': ['y'],
'y': ['x'],
'i': ['j','k'],
'j': ['i','k'],
'k': ['i','j']}
seen = set()
to_remove = []
for key, val in d.items():
entry = tuple(sorted(val.copy() + [key]))
to_remove.append(key) if entry in seen else seen.add(entry)
for key in to_remove:
del d[key]
print(d)
Output:
{'a': ['b'], 'c': ['d'], 'x': ['y'], 'i': ['j', 'k']}
Here is a solution how you can have it in one single loop with a dict comprehension as a one liner:
{k: v for i, (k, v) in enumerate(d.items()) if not set(list(d.keys())[:i]).intersection(v)}
And if you want to have it really fast:
s = set()
dmod = {}
for k, v in d.items():
s.add(k)
if not s.intersection(v):
dmod[k] = v
Both approaches assume your dict is named d.
Result:
# {'a': ['b'], 'c': ['d'], 'x': ['y'], 'i': ['j', 'k']}
However, I have to state here that your text description does not suit the expected example. It would be nice if you could update that.
Besides that: are you aware, that the algorithm you ask for is completely order dependent? No solution which returns the result you want will work reliably prior python 3.6 without explicitely using ordered dicts.
I don't know your use case, but is it ok that applying the same algorithm to a e.g. backwards ordered dict creates a different result?
Another one liner:
>>> d = {'a': ['b'], 'c': ['d'], 'x': ['y'], 'y': ['x'], 'i': ['j','k'], 'j': ['i','k'], 'k': ['i','j']}
>>> dict({tuple(sorted((k, *v))):(k, v) for k, v in d.items()}.values())
{'a': ['b'], 'c': ['d'], 'y': ['x'], 'k': ['i', 'j']}
The inner dict is built with the sorted tuples (key, value1, value2, ...) as keys and the (key, [value1, value2, ...]) pairs as values. Obviously, for every sorted tuple, you keep the last (key, [value]) pair (this matters only if the dict keys are ordered, Python >= 3.6). Then build a dict with these (key, [value]) pair.
If you want to get only the first key-value (Python >= 3.6), just reverse the order of iteration of the original dict:
>>> dict({tuple(sorted((k, *v))):(k, v) for k, v in sorted(d.items(), reverse=True)}.values())
{'x': ['y'], 'i': ['j', 'k'], 'c': ['d'], 'a': ['b']}
If that's not clear, here's a more simple example. I want to keep the first list having a given length in a list:
>>> L = [[1], [2], [1,2], [2,3,4], [3], [5,2], [7,8,9]]
>>> {len(v): v for v in reversed(L)}
{3: [2, 3, 4], 2: [1, 2], 1: [1]}
We see that only the first value is kept:
[*[1]*, [2], *[1,2]*, *[2,3,4]*, [3], [5,2], [7,8,9]]
Because this first value is the last to be added to the dict and overwrite the next one (or previous one in reverse order).
I have this dictionary:
d1={
'a':['b','c','b'],
'b':['a','d','e']
}
it is sort of a directed graph. For example, d1['a'] points twice to 'b', and once to 'c' (see graph below)
What I want is to create two dictionaries out of d1 - pointing_to and pointed_by with values describing how many times they are pointing to or pointed by, respectively.
pointing_to={
'a':{'b':2,'c':1},
'b':{'a':1,'d':1,'e':1},
}
pointed_by={
'a':{'b':1},
'b':{'a':2},
'c':{'a':1},
'd':{'b':1},
'e':{'b':1}
}
You can use some collections utils to get to your output:
from collections import Counter, defaultdict
d1 = {'a': ['b', 'c', 'b'], 'b': ['a', 'd', 'e']}
pointed_to = {k: Counter(v) for k, v in d1.items()}
pointed_from = defaultdict(dict)
for k, v in pointed_to.items():
for k_, v_ in v.items():
pointed_from[k_][k] = v_
# pointed_to
{'a': Counter({'b': 2, 'c': 1}),
'b': Counter({'d': 1, 'a': 1, 'e': 1})}
# pointed_from
defaultdict(<class 'dict'>, {'d': {'b': 1},
'a': {'b': 1},
'c': {'a': 1},
'b': {'a': 2},
'e': {'b': 1}})
Note that both Counter and deafultdict are subclasses of dict, so these two can, for all intents and purposes, be used as your desired output dicts.
If you really want dict objects, you can easily do that:
pointed_to = {k: dict(v) for k, v in pointed_to.items()}
pointed_from = dict(pointed_from)
I have the following lists:
a = ['A', 'B', 'C', 'C']
b = ['2', '3', 2, 3]
I am zipping them as follows in order to get a dict:
a_dict = dict(zip(a,b))
However, since the final object is a dict I cant have repeated keys:
{'A': '2', 'B': '3', 'C': 3}
Which alternatives can I have in order to have something like this? (*):
{'A': '2', 'B': '3', 'C':2, 'C': 3}
I tried to convert everything as tuples, however I am using a pop to replace some keys and values from the dictionary:
data['A'] = data.pop('B')
Therefore, I cant use a tuple format. Therefore, given the above two lists, how can I get (*)?
The most common way to resolve key conflicts while still maintaining most of the benefit of the quick indexing of a dict is to turn the values into lists:
d = {}
for k, v in zip(a, b):
d.setdefault(k, []).append(v)
so that d becomes:
{'A': ['2'], 'B': ['3'], 'C': [2, 3]}
Your desired output is not achievable by using dicts. You could either resolve the name conflict by using #blhsing's answer, or use sets to get somewhat close to your desired result as I suspect that you want to check for already existing combinations in a data structure because you tried using tuples.
c = set(zip(a, b))
so c becomes:
{('B', '3'), ('C', 3), ('A', '2'), ('C', 2)}
Or defaultdict of collections:
from collections import defaultdict
d=defaultdict(list)
for k,v in zip(a,b):
d[k].append(v)
And now:
print(dict(d))
Output:
{'A': ['2'], 'B': ['3'], 'C': [2, 3]}
If care about single element lists:
print({k:(v if len(v)-1 else v[0]) for k,v in d.items()})
Output:
{'A': '2', 'B': '3', 'C': [2, 3]}