add a second value to a key (dict) python - python

I need to make sure I don't have more than one of the same keys, if so, leave the first one and add their value (make it a list) to the existing key
this is what I tried:
my_dict = {1: "A", 2: "B", 1: "C"}
new_dict={}
list_keys = list(my_dict.keys())
list_values = list(my_dict.values())
for i in range(len(list_values)):
if list_keys[i] in new_dict.keys():
new_dict[list_keys[i]].append(list(list_values[i]))
else:
new_dict.update({list_keys[i]: list_values[i]})
return new_dict
The result required:
{1: ["A", "C"], 2: ["B"]}

The most concise way of reversing a dict like that uses a defaultdict:
from collections import defaultdict
d = {"A": 1, "B": 2, "C": 1}
rev = defaultdict(list)
for k, v in d.items():
rev[v].append(k)
rev
# defaultdict(<class 'list'>, {1: ['A', 'C'], 2: ['B']})

That first line doesn't make sense. A dictionary cannot have two values for the same key, so when you run that first line, the resulting dictionary is:
my_dict = {1: 'A', 2: 'B', 1: 'C'}
print(my_dict)
# {1: 'C', 2: 'B'}
What you could do is iterate over lists of desired keys and values, and build the dictionary that you want that way:
my_keys = [1, 2, 1]
my_vals = ['A', 'B', 'C']
my_dict = {}
for k, v in zip(my_keys, my_vals):
if k in my_dict.keys():
if not isinstance(my_dict[k], list):
my_dict[k] = [my_dict[k]] # convert to a list
my_dict[k].append(v)
else:
my_dict[k] = v
print(my_dict)
# {1: ['A', 'C'], 2: 'B'}
Based on the comments, you originally had a dictionary in_dict = {'A': 1, 'B': 2, 'C':1}. Given this in_dict, you can get the desired result by setting my_keys = in_dict.values() and my_vals = in_dict.keys() in the code above.

Using comprehensions if you want
a = {"A":1, "B":2, "C":1}
{value: [item_[0] for item_ in a.items() if item_[1] == value] for value in set(a.values())}
Output
{1: ['A', 'C'], 2: ['B']}

Related

How to merge keys of dictionary which have the same value?

I need to combine two dictionaries by their value, resulting in a new key which is the list of keys with the shared value. All I can find online is how to add two values with the same key or how to simply combine two dictionaries, so perhaps I am just searching in the wrong places.
To give an idea:
dic1 = {'A': 'B', 'C': 'D'}
dic2 = {'D': 'B', 'E': 'F'}
Should result in:
dic3 = {['A', 'D']: 'B', 'C': 'D', 'E': 'F'}
I am not sure why you would need such a data structure, you can probably find a better solution to your problem. However, just for the sake of answering your question, here is a possible solution:
dic1 = {'A':'B', 'C':'D'}
dic2 = {'D':'B', 'E':'F'}
key_list = list(dic2.keys())
val_list = list(dic2.values())
r = {}
for k,v in dic1.items():
if v in val_list:
i = val_list.index(v) #get index at value
k2 = key_list[i] #use index to retrive the key at value
r[(k, k2)] = v #make the dict entry
else:
r[k] = v
val_list = list(r.values()) #get all the values already processed
for k,v in dic2.items():
if v not in val_list: #if missing value
r[k] = v #add new entry
print(r)
output:
{('A', 'D'): 'B', 'C': 'D', 'E': 'F'}
You can't assign a list as a key in a python dictionary since the key must be hashable and a list is not an ashable object, so I have used a tuple instead.
I would use a defaultdict of lists and build a reversed dict and in the end reverse it while converting the lists to tuples (because lists are not hashable and can't be used as dict keys):
from collections import defaultdict
dic1 = {'A':'B', 'C':'D'}
dic2 = {'D':'B', 'E':'F'}
temp = defaultdict(list)
for d in (dic1, dic2):
for key, value in d.items():
temp[value].append(key)
print(temp)
res = {}
for key, value in temp.items():
if len(value) == 1:
res[value[0]] = key
else:
res[tuple(value)] = key
print(res)
The printout from this (showing the middle step of temp) is:
defaultdict(<class 'list'>, {'B': ['A', 'D'], 'D': ['C'], 'F': ['E']})
{('A', 'D'): 'B', 'C': 'D', 'E': 'F'}
If you are willing to compromise from 1-element tuples as keys, the second part will become much simpler:
res = {tuple(value): key for key, value in temp.items()}

How to selectively create a dictionary from an existing one?

I have two dictionaries like below which have common keys:
dictionary1 = {1: 'a', 2: 'b' , 3: 'c'}
dictionary2 = {1: 'no', 2: 'yes' ,3:'yes'}
I want to create a new dictionary with the key and values of dictionary1 only if the corresponding values of the dictionary2 key has "yes".
Expected output:
{2: 'b', 3: 'c'}
What I have tried:
dictionary1 = {1: 'a', 2: 'b' , 3: 'c'}
dictionary2 = {1: 'no', 2: 'yes' ,3:'yes'}
common_pairs = dict()
for key,value in dictionary2.items():
for key,v in dictionary1.items():
if(value == "yes"):
common_pairs[key] = v
You don't need a nested for loop. Just a single iteration over dictionary1 items with corresponding O(1) lookup in dictionary2:
With a dict comprehension this would look like:
>>> dictionary1 = {1: 'a', 2: 'b' , 3: 'c'}
>>> dictionary2 = {1: 'no', 2: 'yes' ,3:'yes'}
>>> new = {k: v for k, v in dictionary1.items() if dictionary2[k] == 'yes'}
>>> new
{2: 'b', 3: 'c'}
With a traditional for loop:
>>> new = {}
>>> for k, v in dictionary1.items():
... if dictionary2[k] == 'yes':
... new[k] = v
...
>>> new
{2: 'b', 3: 'c'}
You could do this in a dictionary comprehension:
common_pairs = { key:value for key,value in dictionary1.items()
if dictionary2.get(key,"") == "Yes" }
The get function provides a default value if the key is not present. this will prevent errors if a key in dictionary1 is absent from dictionary2.
You can just iterate through dict2, check if the element is in dict1 and that the key is yes, and then add it to the dictionary.
dictionary1 = {1: 'a', 2: 'b' , 3: 'c'}
dictionary2 = {1: 'no', 2: 'yes' ,3:'yes'}
common_pairs = dict()
for key in dictionary2:
if key in dictionary1 and dictionary2[key] == 'yes':
common_pairs[key] = dictionary1[key]

Compare dicts and merge them. No overwrite and no duplicate values

I made a mistake in my question here (wrong requested input and expected output):
Comparing dicts, updating NOT overwriting values
I am not looking for this solution:
Combining 2 dictionaries with common key
So this question is not a duplicate
Problem statement:
requested input:
d1 = {'a': ['a'], 'b': ['b', 'c']}
d2 = {'b': ['c', 'd'], 'c': ['e','f']}
expected output (I don't care about the order of the keys / values!):
new_dict = {'a': ['a'], 'b': ['b', 'c', 'd'], 'c': ['e', 'f']}
The solution in Combining 2 dictionaries with common key
gives following output:
new_dict = {'a': ['a'], 'b': ['b', 'c', 'c', 'd'], 'c': ['e', 'f']}
I don't want the duplicates to be stored.
My solution (it works but it is not so efficient):
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
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)
Here is how I would go about it:
d1 = {'a': ['a'], 'b': ['b', 'c']}
d2 = {'b': ['c', 'd'], 'c': ['e','f']}
dd1 = {**d1, **d2}
dd2 = {**d2, **d1}
{k:list(set(dd1[k]).union(set(dd2[k]))) for k in dd1}
Produces the desired result.
I suggest using a default dictionary collection with a set as a default value.
It guarantees that all values will be unique and makes the code cleaner.
Talking about efficiecy it's O(n^2) by time.
from collections import defaultdict
d1 = {'a': ['a'], 'b': ['b', 'c']}
d2 = {'b': ['c', 'd'], 'c': ['e','f']}
new_dict = defaultdict(set)
for k, v in d1.items():
new_dict[k] = new_dict[k].union(set(v))
for k, v in d2.items():
new_dict[k] = new_dict[k].union(set(v))
Try this code. You can remove deep copy if modifications in the initial array are fine for you.
import copy
def merge(left, right):
res = copy.deepcopy(left)
for k, v in right.items():
res[k] = list(set(res[k]).union(v)) if k in res else v
return res
Simple if statement if you don't want to use a Set.
d3 = dict(d2)
for k,v in d1.items():
if k not in d3:
d3[k] = v
else:
for n in d1[k]:
if n not in d3[k]:
d3[k].append(n)

switch key and values in a dict of lists

Hello Stackoverflow people,
I have a nested dictionary with lists as values and I want to create a dict where all the list entries get their corresponding key as value.
Example time!
# what I have
dict1 = {"A":[1,2,3], "B":[4,5,6], "C":[7,8,9]}
# what I want
dict2 = {1:"A", 2:"A", 3:"A", 4:"B", 5:"B", 6:"B", 7:"C", 8:"C", 9:"C"}
Any help will be much appreciated!
Try this
dict1 = {"A":[1,2,3], "B":[4,5,6], "C":[7,8,9]}
dict2= {}
for keys,values in dict1.items():
for i in values:
dict2[i]=keys
print(dict2)
Output
{1: 'A', 2: 'A', 3: 'A', 4: 'B', 5: 'B', 6: 'B', 7: 'C', 8: 'C', 9: 'C'}
Hope it helps
Use dictionary comprehension:
d = {'a': 'b', 'c': 'd', 'e': 'f'}
d2 = dict((v1, k) for k, v in d.items() for v1 in v) # Here is the one-liner
assuming your key: value dictionary contains list as a value and using dict comprehension.
Using a second loop to iterate over the list present in original dictionary.
{item: key for key, value in dict1.items() for item in value}

Find same dictionary by value

I have dictionary like below
dict1 = {'a':{'a':20, 'b':30}, 'b':{'a':30, 'b':40}, 'c':{'a':20, 'b':30}, 'd':{'a':30, 'b':40}}
Then in following dictionary two dictionaries are same, so expected result will be like below
result = [['a','c'],['b','d']]
>>> seen = {}
>>> dict1 = {'a':{'a':20, 'b':30}, 'b':{'a':30, 'b':40}, 'c':{'a':20, 'b':30}, 'd':{'a':30, 'b':40}}
>>> for k in dict1:
fs = frozenset(dict1[k].items())
seen.setdefault(fs, []).append(k)
>>> seen.values() # note: unordered
[['a', 'c'], ['b', 'd']]
If order is needed:
>>> from collections import OrderedDict
>>> dict1 = {'a':{'a':20, 'b':30}, 'b':{'a':30, 'b':40}, 'c':{'a':20, 'b':30}, 'd':{'a':30, 'b':40}}
>>> seen = OrderedDict()
>>> for k in sorted(dict1):
fs = frozenset(dict1[k].items())
seen.setdefault(fs, []).append(k)
>>> seen.values()
[['a', 'c'], ['b', 'd']]
Note: This code is currently cross-compatible on Python 2/3. On Python 2 you can make it more efficient by using .iteritems() instead of .items()
A quick one: 1st get different values, then list comprehension.
>>> values = []
>>> for k in dict1:
if dict1[k] not in values:
values.append(dict1[k])
>>> values
[{'a': 20, 'b': 30}, {'a': 30, 'b': 40}]
>>> [[k for k in dict1 if dict1[k] == v] for v in values]
[['a', 'c'], ['b', 'd']]

Categories

Resources