If dict2 value = dict1 key, replace entire dict2 value with dict1 value - python

I have two dictionaries. In both dictionaries, the value of each key is a single list. If any element in any list in dictionary 2 is equal to a key of dictionary 1, I want to replace that element with the first element in that dictionary 1 list.
In other words, I have:
dict1 = {'IDa':['newA', 'x'], 'IDb':['newB', 'x']}
dict2 = {1:['IDa', 'IDb']}
and I want:
dict2 = {1:['newA', 'newB']}
I tried:
for ID1, news in dict1.items():
for x, ID2s in dict2.items():
for ID in ID2s:
if ID == ID1:
print ID1, 'match'
ID.replace(ID, news[0])
for k, v in dict2.items():
print k, v
and I got:
IDb match
IDa match
1 ['IDa', IDb']
So it looks like everything up to the replace method is working. Is there a way to make this work? To replace an entire string in a value-list with a string in another value-list?
Thanks a lot for your help.

Try this:
dict1 = {'IDa':['newA', 'x'], 'IDb':['newB', 'x']}
dict2 = {1:['IDa', 'IDb']}
for key in dict2.keys():
dict2[key] = [dict1[x][0] if x in dict1.keys() else x for x in dict2[key]]
print dict2
this will print:
{1: ['newA', 'newB']}
as required.
Explanation
dict.keys() gives us just the keys of a dictionary (i.e. just the left hand side of the colon). When we use for key in dict2.keys(), at present our only key is 1. If the dictionary was larger, it'd loop through all keys.
The following line uses a list comprehension - we know that dict2[key] gives us a list (the right side of the colon), so we loop through every element of the list (for x in dict2[key]) and return the first entry of the corresponding list in dict1 only if we can find the element in the keys of dict1 (dict1[x][0] if x in dict1.keys) and otherwise leave the element untouched ([else x]).
For example, if we changed our dictionaries to be the following:
dict1 = {'IDa':['newA', 'x'], 'IDb':['newB', 'x']}
dict2 = {1:['IDa', 'IDb'], 2:{'IDb', 'IDc'}}
we'd get the output:
{1: ['newA', 'newB'], 2: ['newB', 'IDc']}
because 'IDc' doesn't exist in the keys of dict1.

You could also use dictionary comprehensions, but I am not sure that they are working in Python 2.7, it may be limited to Python 3 :
# Python 3
dict2 = {k: [dict1.get(e, [e])[0] for e in v] for k,v in dict2.items()}
edit: I just checked, this is working in Python 2.7. However, dict2.items() should be replaced by dict2.iteritems() :
# Python 2.7
dict2 = {k: [dict1.get(e, [e])[0] for e in v] for k,v in dict2.iteritems()}

This was a fun one!
dict2[1] = [dict1[val][0] if val in dict1 else val for val in dict2[1]]
Or, here is the same logic without list comprehension:
new_dict = {1: []}
for val in dict2[1]:
if val in dict1:
new_dict[1].append(dict1[val][0])
else:
new_dict[1].append(val)
dict2 = new_dict

Related

Adding a Key-Value pair in a list in an empty dictionary if the keys are the same [duplicate]

This question already has answers here:
How do I merge two dictionaries in a single expression in Python?
(43 answers)
Closed 9 months ago.
How can I print a dictionary as a union of given dictionaries & appending the values if the keys are equal?
Input:
dict_1 = {
"x":[1,"hello"],
"y":[2,"world"],
"z":3
}
dict_2 ={
"p":4,
"q":19,
"z":123
}
Output:
dict_3={"x":[1,"hello"],
"y":[2,"world"],
"z":[3,123],
"p":4,
"q":19,
}
Try this: Check out the inline comments for explanation of what is happening.
for key,value in dict1.items(): # loop through dict1
if key in dict2: # see if each key in dict1 exists in dict2
if isinstance(dict2[key], list): # if it is in dict2 check if the value is a list.
dict2[key].append(value) # if it is a list append the dict1 value
else: # otherwise
dict2[key] = [dict2[key], value] # create a new list and stick
# the values for dict1 and
# dict2 inside of it
else: # if the key is not in dict2
dict2[key] = value # set the new key and value in dict2
print(dict2) # output
if you want to check for other collections try this
for key,value in dict1.items(): # loop through dict1
if key in dict2: # see if each key in dict1 exists in dict2
if hasattr(dict2[key], '__iter__'): # if it is in dict2 check if the value is a list.
if value not in dict2[key]:
try:
dict2[key].append(value)
except:
dict2[key].add(value)
finally:
dict2[key] = tuple(list(dict2[key]) + [value])
else: # otherwise
dict2[key] = [dict2[key], value] # create a new list and stick
# the values for dict1 and
# dict2 inside of it
else: # if the key is not in dict2
dict2[key] = value # set the new key and value in dict2
print(dict2) # output
Try this
# use the union of the keys and construct a list if a key exists in both dicts
# otherwise get the value of the key from the dict it exists in
{k:[dict_1[k], dict_2[k]] if all(k in d for d in [dict_1, dict_2]) else (dict_1.get(k) or dict_2.get(k)) for k in set(dict_1).union(dict_2)}
# {'x': [1, 'hello'], 'q': 19, 'y': [2, 'world'], 'z': [3, 123], 'p': 4}
This can be written (hopefully) a little more readably by using next and walrus operator:
{k: next(i for i in v if i is not None) if None in (v:=[dict_1.get(k), dict_2.get(k)]) else v for k in set(dict_1).union(dict_2)}
The same code as a normal loop:
dict_3 = {}
# loop over the union of the keys
for k in set(dict_1).union(dict_2):
# construct the list from the values
v = [dict_1.get(k), dict_2.get(k)]
# if a key doesn't exist in one of the dicts, it will dict.get() will give None
if None in v:
# in which case, get the non-None value
dict_3[k] = next(i for i in v if i is not None)
# otherwise, i.e. a key exists in both dicts,
else:
dict_3[k] = v

Matching the values of one dictionary to the keys of another dictionary (Python)

Evening All,
Hope you are well.
My Objective
I am trying to match the values of one dictionary to the keys of another.
dict1 has keys but no values
dict2 has keys and values
dict2 has values that can be found as keys in dict1. I'm attempting to write code that identifies which values in dict2 match the keys in dict1.
My Attempt
Commented code is below.
dict1 = {('dict1_key1',): [], ('dict1_key2',): []} #dictionary with keys, but no values;
for i in dict2.keys(): #iterate through the keys of dict2
for x in dict2[i]: #reaching every element in tuples in dict2
if x == dict1.keys(): #if match found in the name of keys in dict1
print(f"{i} holding {x}.") #print which key and value pair in dict 2 match the keys in dict1
The code works if I write the for loop as follows:
for i in dict2.keys(): #iterate through the keys of dict2
for x in dict2[i]: #reaching every element in tuples in dict2
if x == dict1_key1 or x == dict1_key2(): #if match found in the name of keys in dict1
print(f"{i} holding {x}.") #print which key and value pair in dict 2 match the keys in dict1
However, dict1 in reality needs to be able to contain an varying number of keys which is why I had hoped that if x == dict1.keys(): would work.
Any feedback would be greatly appreciated.
#Mark Meyer
Examples values as requested:
dict1 = {('Tower_001',): [], ('Tower_002'): []}
dict2 = {1: 'Block_A', 'Tower_001'] #first key in dict2
#skipping keys 2 through 13
{14: ['Block_N', 'Tower_002']#last key in dict2
You can make sets of all the value in the dict1.keys and dict2.value. Then just take the intersection of those sets to find keys that are also values:
dict1 = {('Tower_001',): [], ('Tower_005',): [], ('Tower_002',): []}
dict2 = {1: ['Block_A', 'Tower_001'], #first key in dict2
14: ['Block_N', 'Tower_002']} #last key in dict2
set(k for l in dict2.values() for k in l) & set(k for l in dict1.keys() for k in l)
# {'Tower_001', 'Tower_002'}

iterate 2 dicts and compare values then append inner list

I am faced with a situation where I need to iterate nested dicts with same outermost keys, compare inner key value to inner key value of other dict then append. Below will help to understand:
{AD:{(62,'VMX','Barcelona','ES'): ['123','567','666'}} #dict1 many more rows
{AD:{(151,'CMXS','','ES','62'): ['345','6754']}} #dict 2 many more rows
So I need to iterate both dicts, compare tuple key[0] of dict1 == tuple key[4] of dict2, if they match append inner list in dict1 with inner list in dict2.
after this dict1 looks like
{AD:{(62,'VMX','Barcelona','ES'): ['123','567','666','345','6754'}}
Wrote this code but it not working as expected
for k,v in dict1.items():
if len(v)!= 0:
for c,a in dict2.items():
if len(a)!= 0:
for k2,v2 in v.items():
for c2,a2 in a.items():
if str(k2[0]) == c2[4]:
v2.append(a2)
dict1 = {"AD":{(62,'VMX','Barcelona','ES'): ['123','567','666']}} #dict1 many more rows
dict2 = {"AD":{(151,'CMXS','','ES','62'): ['345','6754']}} #dict 2 many more rows
# create a simplified map of dict2
dict3 = {}
for outer_key, outer_value_dict in dict2.items():
for inner_key_tuple, inner_value_list in outer_value_dict.items():
new_key = (outer_key, inner_key_tuple[4]) # e.g. (AD, 62)
dict3.setdefault(new_key, []).extend(inner_value_list)
# now modify dict1 using dict3 instead of dict2
for outer_key, outer_value in dict1.items():
for inner_key_tuple, inner_value_list in outer_value.items():
lookup_key = (outer_key, str(inner_key_tuple[0]))
# search dict3 using the lookup_key.
# if not present, get will return an empty list
list_to_extend = dict3.get(lookup_key, [])
inner_value_list.extend(list_to_extend)
print(dict1)
Output
/tmp $ python test.py.py
{'AD': {(62, 'VMX', 'Barcelona', 'ES'): ['123', '567', '666', '345', '6754']}}
Based on the comments, since you wanted to know how to avoid one of the loops - here's an updated version
for k,v in dict1.items():
a = dict2.get(k)
if a is None or len(v) == 0:
continue
for k2,v2 in v.items():
for c2,a2 in a.items():
if str(k2[0]) == c2[4]:
v2.append(a2)
The for loops are placed correctly as long as the example goes.
What do you mean by unexpectedly?
Do you mean this?
{'AD': {(62, 'VMX', 'Barcelona', 'ES'): ['123', '567', '666', ['345', '6754']]}}
That extra array within the array?
Because if so, the answer would be to switch the .append() with a .extend()

Merge 2 dictionaries in Python

I have 2 dictionaries.
dict1={('SAN RAMON', 'CA'): 1, ('UPLAND', 'CA'): 4, ('POUGHKEESIE', 'NY'): 3, ('CATTANOOGA', 'TN'): 1}
dict2={('UPLAND', 'CA'): 5223, ('PORT WASHING', 'WI'): 11174, ('PORT CLINTON', 'OH'): 6135, ('GRAIN VALLEY', 'MO'): 10352, ('GRAND JUNCTI', 'CO'): 49688, ('FAIRFIELD', 'IL'): 5165}
These are just samples, in reality each dict has hundreds of entries. I am trying to merge the two dictionaries and create dict 3 that contains {dict1.values(): dict2.values()} but only if that city appears in both dicts. So, one entry in dict3 would look like
{4:5223} # for 'UPLAND', 'CA' since it appears in both dict1 and dict2
This is just a small step in a larger function I am writing. I was going to try something like :
for item in dict1.keys():
if item not in dict2.keys():
del item
return dict[(dict1.keys())=(dict2.keys())]
I can't figure out how to make sure the number of complaints from dict1 matches the same city it is being referred to in dict2.
Here's what I think you want (demo):
dict3 = dict((dict1[key], dict2[key]) for key in dict1 if key in dict2)
Expanded a little, it looks like this:
dict3 = {}
for key in dict1:
if key in dict2:
dict3[dict1[key]] = dict2[key]
The common keys are:
set(dict1.keys()) & set(dict2.keys())
create dict 3 that contains {dict1.values(): dict2.values()}
This doesn't make sense, dictionaries are key-value pairs... what do you really want? Tip:
dict3 = {}
for k in set(dict1.keys()) & set(dict2.keys()):
dict3[dict1[k]]=dict2[k]
{4: 5223}
The straightforward way would be to check each key in one for membership in the other:
result = {}
for key in dict1:
if key in dict2:
result[dict1[key]] = dict2[key]
You could also try converting them into a set or frozenset and taking their intersection, but it's not clear to me whether that will be faster or not:
keys_in_both = frozenset(dict1) & frozenset(dict2)
result = dict((dict1[key], dict2[key]) for key in keys_in_both)

update one dictionary with another by adding values rather then replacing it

I have many dictionaries like this:
dict1 = {1:[1,2,3],2:[2,3,4]}
dict2 = {2:[3,4,5],3:[4,5,6]}
I need to get
dict = {1:[1,2,3],2:[2,3,4,3,4,5],3:[4,5,6]}
# ^
# | order is unimportant
What is the best way of doing it?
Simple iteration an extending list...
for key, value in dict2.iteritems():
dict1.setdefault(key, []).extend(value)
Iterate through the keys of dict2; if the same key exists in dict1, concatenate the lists and set in dict1; otherwise just set in dict1
dict1 = {1:[1,2,3],2:[2,3,4]}
dict2 = {2:[3,4,5],3:[4,5,6]}
dicts = [dict1, dict2]
new_dict = {}
for d in dicts:
for k, v in d.iteritems():
if new_dict.has_key(k):
new_dict[k] = new_dict[k] + v
else:
new_dict[k] = v
a = {'a' : [1,2], 'b' : [3,4]}
b = {'a' : [3,4], 'b' : [1,2]}
for key in a.keys():
for elem in a[key]:
b[key].append(elem)
Oh, maybe there's some clever way to do it with reduce, but why not just write code like a normal person.
dict = {}
for each_dict in (dict1, dict2, ...): # ... is not real code
for key, value in each_dict:
if not dict.has_key(key):
dict[key] = []
dict[key] += value # list append operator
I have many dictionaries like this:
This way lets you "glue together" multiple dictionaries at a time:
dict(
(k, sum((d.get(k, []) for d in dicts), []))
for k in set(sum((d.keys() for d in dicts), []))
)

Categories

Resources