Merge two dictionaries' values by keys - python

Hi I want to merge two dictionaries' values if the keys are the same.
DIC_01
{'A': ['Zero'],
'B': ['Zero'],
'C': ['Zero'],
'D': ['Zero']}
DIC_02
{'A': [2338.099365234375,
-3633.070068359375,
-73.45938873291016],
'D':[2839.291015625,
-2248.350341796875,
1557.59423828125]}
Idea output
{'A': [[2338.099365234375,
-3633.070068359375,
-73.45938873291016],['Zero']],
'D': [[2839.291015625,
-2248.350341796875,
1557.59423828125]['Zero']]}
Output for the Keys that cannot be found
{'B': ['Zero'],'C': ['Zero']}
I tried
NO_MATCH={}
for k in DIC_01.keys():
DOC={}
for k2 in DIC_02.keys():
if k == k2:
DOC = k.values().update(k2.values())
else:
NO_MATCH.update(DIC_01)
There is nothing in DOC and all the dictionary elements are in NO_MATCH, no error message. don't know where goes wrong, also I think there must be better ways to do this.
Thank you!

Edited: You can declare two separate dictionaries and iterate through all the keys of both dictionaries. For every iteration, check if the key exists in DIC_02 and DIC_01 and concatenate the two corresponding lists
match, no_match = {}, {}
for i in {**DIC_01,**DIC_02}.keys():
if i in DIC_01 and i in DIC_02:
match[i] = DIC_01[i] + DIC_02[i]
else:
no_match[i] = DIC_01.get(i,[]) + DIC_02.get(i,[])

It's not particularly fancy but this should solve what you're looking for
def merge(a, b):
out = {}
for key in a.keys() | b.keys():
if key in a and key in b:
out[key] = [a[key], b[key]]
elif key in a:
out[key] = a[key]
else:
out[key] = b[key]
return out
where a and b are dicts. The | takes the union of the two key sets.

As for why your code goes wrong.
NO_MATCH={}
for k in DIC_01.keys():
DOC={} # (1)
for k2 in DIC_02.keys(): # (2)
if k == k2:
DOC = k.values().update(k2.values()) # (3)
else:
NO_MATCH.update(DIC_01) # (4)
Not there! Everything you define inside a loop, will be redefined everytime the loop goes around.
This goes to the else block even if there's a matched key. For instance, in your case, it compares A in DIC_01 with A in DIC_02, "ok, A matched". BUT, then it proceeds to compare A in DIC_01 with D in DIC_02, "ok, A not found in DIC_02, not matched, add to NOT_MATCH" which is wrong, because A IS a matched key and A IS in DIC_02.
Not sure how you didn't get an error, seems very erroneous.
This lines add the entire DIC_01 to NO_MATCH, wrong!
FIX:
MATCH = {}
NO_MATCH = {}
# This goes through all keys in DIC_01. If a key is also found in DIC_02,
# it's a "matched" key so it adds that key to the MATCH variable. If it's
# not in DIC_02, it's a "no matched" key -> add key to NO_MATCH variable.
for k in DIC_01.keys():
if k in DIC_02.keys():
MATCH[k] = [DIC_01[k], DIC_02[k]]
else:
NO_MATCH[k] = DIC_01[k]
# BUT...We are still missing the keys that are only in DIC_02. So we need
# another loop
for k in DIC_02.keys():
if k not in DIC_01.keys():
NO_MATCH[k] = DIC_02[k]
# This is the same as the loop above, without the if block.
BETTER WAY
Some list comprehensions would keep things clean.
MATCH = {key:[DIC_01[key], DIC_02[key]] for key in DIC_01 if key in DIC_02}
unmatch_1 = {key:DIC_01[key] for key in DIC_01 if key not in DIC_02}
unmatch_2 = {key:DIC_02[key] for key in DIC_02 if key not in DIC_01}
NOT_MATCH = {**unmatch_1, **unmatch_2}
EXPLAINATION:
MATCH = {key:[DIC_01[key], DIC_02[key]] for key in DIC_01 if key in DIC_02}
This, in English, create a new dictionary called match.For every key in DIC_01, if the key is also in DIC_02, create the same key in match and assign both the values of that key from DIC_01 and DIC_02.
unmatch_1 = {key:DIC_01[key] for key in DIC_01 if key not in DIC_02}
This ... For every key in DIC_01, if it's not in DIC_02, create a key and assign the associated value from DIC_01
unmatch_2 = {key:DIC_02[key] for key in DIC_02 if key not in DIC_01}
This ... For every key in DIC_02, if it's not in DIC_01, create a key and assign the associated value from DIC_02
UNMATCH = {**unmatch_1, **unmatch_2}
This ... is a cool way of merging 2 dictionaries (Only for Python 3.5 and up)

This looks like a great use for ChainMap
>>> a={'A': ['Zero'],
... 'B': ['Zero'],
... 'C': ['Zero'],
... 'D': ['Zero']}
>>> b={'A': [2338.099365234375,
... -3633.070068359375,
... -73.45938873291016],
... 'D':[2839.291015625,
... -2248.350341796875,
... 1557.59423828125]}
>>> map=ChainMap(b,a)
>>> map['A']
[2338.099365234375, -3633.070068359375, -73.45938873291016]
>>> map['C']
['Zero']
The key precedence will be on the order of the dictionaries, so if you can't control order or if the ['Zero'] are mixed and matched: this way can't help.

Related

Search dictionary keys with regex

I have defined a dictionary with string keys:
{'dummy': 0, 'K1::foo(bar::z(x,u))': 1, 'K2::foo()': 2}
I want to search for key pattern (not the exact word), so if 'foo' in my_dict: should return true.
yax = 'foo'
if yax in my_dict:
# Should definitely go here
value = my_dict[yax]
print(value)
else:
# Just for error checking that the given name doesn't exist in dictionary
print("Given value does not exist")
But the above code goes to the else section.
In the example, foo exists in two keys. That doesn't matter. the first match is OK. As another example, if I search for bar, the if statement should be true, too.
First, know that it is not a good approach to have to search through dictionary keys. The purpose of a dictionary is to enable O(1) access to the values using hashed keys.
That said, you can loop over the keys.
Searching any substring:
d = {'dummy': 0, 'K1::foo(bar::z(x,u))': 1, 'K2::foo()': 2}
[k for k in d if 'foo' in k]
Searching an independent word:
import re
[k for k in d if re.search(r'\bfoo\b', k)]
output: ['K1::foo(bar::z(x,u))', 'K2::foo()']
as dictionary comprehension:
{k:v for k,v in d.items() if 'foo' in k}
output: {'K1::foo(bar::z(x,u))': 1, 'K2::foo()': 2}

if statement doesn't work properly in python

d={1:'a', 2:'b', 3:'c', 4:'a', 5:'d', 6:'e', 7:'a', 8:'b'}
value = raw_input("Choose a value to be searched: ")
data = ""
if value in d:
data = d.keys["value"]
print(data)
else:
print "There isn't such value in the dictionary"
So I write 'a' and I want to get the key '1'
but it skips "data = d.keys["value"] print(data)" and it prints me the message of "else"
What have I done wrong?
Containment checks for dict check the keys, not the values, and 'a' is a value in the dict, not a key.
The simplest fix would be to change your test to:
if value in d.viewvalues(): # d.values() on Python 3
but that's still sub-optimal; you can't perform efficient (O(1)) lookups in the values of a dict (nor can you do d.keys[value] as you seem to think you can; you'd have to perform a second linear scan to find the key, or perform a more complicated single scan to determine if the value exists and pull the key at the same time).
Really though, it seems like you want your dictionary reversed, with the keys as values and vice-versa. Doing it this way:
d = {1:'a', 2:'b', 3:'c', 4:'a', 5:'d', 6:'e', 7:'a', 8:'b'}
d_inv = {v: k for k, v in d.items()} # Make inverted version of d
value = raw_input("Choose a value to be searched: ")
if value in d_inv:
data = d_inv[value]
print(data)
else:
print "There isn't such value in the dictionary"
you can perform the containment check and lookup efficiently (if d isn't otherwise needed, you can just replace d with the same structure as d_inv and use d instead of d_inv uniformly).
As stated, you need the value, here's an alternative
if any(d[value] for value in d):
Then, d.keys["value"] is actually d[value]
You could do something like this:
d={1:'a', 2:'b', 3:'c', 4:'a', 5:'d', 6:'e', 7:'a', 8:'b'}
value = 'q'
data = [key for key, val in d.items() if val == value]
if len(data) > 0:
print(data)
else:
print "There isn't such value in the dictionary"
Then you would get the results
[1, 4, 7]

Adding nonzero items from a dictionary to another dictionary

I have a set of reactions (keys) with values (0.0 or 100) stored in mydict.
Now I want to place non zero values in a new dictionary (nonzerodict).
def nonzero(cmod):
mydict = cmod.getReactionValues()
nonzerodict = {}
for key in mydict:
if mydict.values() != float(0):
nonzerodict[nz] = mydict.values
print nz
Unfortunately this is not working.
My questions:
Am I iterating over a dictionary correctly?
Am I adding items to the new dictionary correctly?
You are testing if the list of values is not equal to float(0). Test each value instead, using the key to retrieve it:
if mydict[key] != 0:
nonzerodict[key] = mydict[key]
You are iterating over the keys correctly, but you could also iterate over the key-value pairs:
for key, value in mydict.iteritems():
if value != 0:
nonzerodict[key] = value
Note that with floating point values, chances are you'll have very small values, close to zero, that you may want to filter out too. If so, test if the value is close to zero instead:
if abs(value) > 1e-9:
You can do the whole thing in a single dictionary expression:
def nonzero(cmod):
return {k: v for k, v in cmod.getReactionValues().iteritems() if abs(v) > 1e-9}
Its simple and you can it by below way -
>>> d = {'a':4,'b':2, 'c':0}
>>> dict((k,v) for k,v in d.iteritems() if v!=0)
{'a': 4, 'b': 2}
>>>
Replace if condition in you code with:
if mydict[key]:
nonzerodict[key] = mydict[key]
Your solution can be further simplified as:
def nonzero(cmod):
mydict = cmod.getReactionValues()
nonzerodict = {key: value for key, value in mydict.iteritems() if value}

How to append a value to a not yet existing key?

I have a dictionary like this:
dct = {'one': 'value',
'two': ['value1','value2','value1'],
'three':['otherValue1','otherValue2','otherValue1'],
'dontCareAboutThisKey':'debug'}
I need to remove duplicate values from the lists. I wrote a function to do this:
no_dups = {}
for keys in dct:
if isinstance(dct[keys], list) and keys != 'dontCareAboutThisKey':
for value in dct[keys]:
if value not in no_dups.values():
no_dups[keys].append(value)
else:
no_dups[keys] = dct[keys]
I'm checking if value of the current key is a list. If no, it just 'copy' key to no_dups dictionary. If it is a list and not a key that I don't care about (there are no duplicates for sure) - it should check if current value already exists in no_dups.values() and append it to current key. Problem is that I'm getting an error:
KeyError: 'two:'
I know it's because I'm trying to add a value to non existing key but I have no idea how to deal with this and make it work.
I think the best way to deal with adding the key and appending at the same time is with dicts' setdefault() method:
no_dups.setdefault(keys,[]).append(value)
But rather than that, you can do this in a more neat way like this:
#remove duplicates
no_dups = {k:list(set(v)) if isinstance(v, list) and k != 'dontCareAboutThisKey' else v
for k,v in dct.items()} # or dct.iteritems() if using python2.x
That hack will, for key value combinations that pass the if test, convert the list into a set (removing duplicates) and then in a list again. For other key value combinations it will leave it intact.
dct = {'one': 'value',
'two': ['value1','value2','value1'],
'three':['otherValue1','otherValue2','otherValue1'],
'dontCareAboutThisKey':'debug'}
set(dct) returns a set, which is a list without duplicates:
for key, value in dct.items():
if not isinstance(value, basestring):
dct[key] = set(value)
If you need a new dictionary you could do:
new_dct = {}
for key, value in dct.items():
if not isinstance(value, basestring):
new_dct[key] = set(value)
else:
new_dct[key] = value
If You want to remove duplicates, just change You list to set, with set() function:
https://docs.python.org/2/tutorial/datastructures.html#sets
It automatically gives You unique set, then You can always change it back to list.

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)

Categories

Resources