Merge two dictionaries conditionally using dict comprehension - python

I'd like two join two dictionaries based on the value of d1 and a substring of the key of d2. The resulting dictionary has the key of d1 with the corresponding value of d2.
d1 = {'web02': '23', 'web01': '50'}
d2 = {'server/dc-50': 's01.local', 'server/dc-23': 's02.local'}
Would result in = {web01:s01.local, web02:s02.local}

I guess this is what you need :
result = {k1:v2 for k1,v1 in d1.items() for k2,v2 in d2.items() if v1 in k2}
Output :
{'web02': 's02.local', 'web01': 's01.local'}

This is done without a nested loop by getting the value using string formatting:
data = {k: d2['server/dc-' + v] for k, v in d1.items()}
Prints:
{'web02': 's02.local', 'web01': 's01.local'}

Related

Split dictionaries into different dictionaries based on the key in python?

Suppose I have a dictionary:
d = {'a_c':1,'b_c':2,'a_d':3,'b_d':4}
how do I split into two based on the last word/letter of the key ('c','d') like this?
d1 = {'a_c':1,'b_c':2}
d2 = {'a_d':3,'b_d':4}
This is one way:
from collections import defaultdict
d = {'a_c':1,'b_c':2,'a_d':3,'b_d':4}
key = lambda s: s.split('_')[1]
res = defaultdict(dict)
for k, v in d.items():
res[key(k)][k] = v
print(list(res.values()))
Output:
[{'a_c': 1, 'b_c': 2}, {'a_d': 3, 'b_d': 4}]
The result is a list of dictionaries divided on the last letter of the key.
You could try something like this:
func = lambda ending_str: {x: d[x] for x in d.keys() if x.endswith(ending_str)}
d1 = func('_c')
d2 = func('_d')
Also, like Marc mentioned in the comments, you shouldn't have two same name keys in the dictionary. It will only keep the last key/value pair in that case.

We're trying to build a small dict that's a combination of two others but we're kinda failing

Write a function combine_dicts(d1, d2) that takes two dictionaries
as input and returns a dictionary that is a combination of them in the
following way:
If a key is only in one of the dictionaries it should be the same in the result.
If a key is in both dictionaries and have the same value (as compared with is in Python) it should be the same in the result.
But if a key is in both dictionaries with di erent values, the value in the result should be a tuple with two entires, the one from d1 and
the one from d2.
Note that this program doesn’t do anything partic- ular when run. It
only exists because it contains this function. The module can be
imported in programs that need that function.
So we came up with a pretty simple code, which we don't know if it's correct. We came up with the idea of including two small dicts at the beginning because the assignment provides no way of testing, so we thought if it worked on the dictionaries it would be fine. Things is, it throws error: TypeError: unhashable type: 'dict'. Can you tell us what we're doing wrong?
d1=dict()
d1={'1':'uno','2':'dos','3':'tres'}
d2=dict()
d2={'1':'ena', '2':'duo', '3':'tres'}
def combine_dicts(d1,d2):
d3={}
for key in (d1, d2):
# Key is in d1 or in d2
if key in d1 or d2:
d3[key]=value
return d3
# Key is in both d1 and d2 and values are the same. The below is incorrect right?
elif key in d1 and d2 and d1[key] is d2[key]:
d3[key]=value
return d3
else:
if key in d1 and d2 and d1[key] is not d2[key]:
t=tuple(d1[key], d2[key])
return t
There are a number of problems here.
Currently in your for loop you set key to be equal to d1 and then d2, when you want to set it equal to each of the keys.
You never set value anywhere
You return while processing the first key, and not after having combined the dictionaries, and sometimes you're not even returning a dictionary. You only want to return d3, and only at the end.
There's no need to create the dicts with dict() before you create them again with a {} expression.
key in d1 or d2 will always evaluate to True, because bool(d2) is True. What you mean to say is key in d1 or key in d2. However, you don't really want to have this particular if statement at all - all of the keys are from either d1 or d2!
These issues are all fixed below:
d1 = {'1': 'uno', '2': 'dos', '3': 'tres'}
d2 = {'1': 'ena', '2': 'duo', '3': 'tres'}
def combine_dicts(d1,d2):
d3={}
for key in set().union(d1, d2):
# Key is in d1 or in d2
if key in d1 and key in d2:
if d1[key] == d2[key]:
d3[key] = d1[key]
else:
d3[key] = (d1[key], d2[key])
elif key in d1:
d3[key] = d1[key]
else:
d3[key] = d2[key]
return d3
print(combine_dicts(d1, d2))
First of all, you seem to not understand how to construct a dict:
d1=dict() # Construct an empty dict
d1={'1':'uno','2':'dos','3':'tres'} # Construct a dict containing 3 keys/values
So you do not need to initialize your variables d1 and d2 with dict() since the construction {key: value} will create a new dict, and thus overwrite the previous value (in your case, an empty dict constructed by dict()).
Next:
for key in (d1, d2):
You are asking to iterate over (d1, d2), but (d1, d2) is actually a tuple containing your two dicts. So you will go through your loop only two times: one time with key = d1 and one time with key = d2. So the code in your loop cannot work since key is a dict and not a key of d1 or d2.
You should first construct a list, or better, a set containing the union of d1.keys() and d2.keys(). You can do it with:
all_keys = set(d1.keys()).union(d2.keys())
Then you must iterate over all_keys and construct your new dict.
for key in all_keys:
if key in d1 and key not in d2:
d3[key] = d1[key]
elif key in d2 and key not in d1:
d3[key] = d2[key]
else:
d3[key] = (d1[key], d2[key])
here ya go! hope this helps. just a couple for loops to process both dictionaries, the second for loop has the if/else logic to check for matching keys and/or matching values
def combine(d1,d2):
d = {}
for k,v in d1.items():
d[k] = v
for k,v in d2.items():
if k in d1.keys():
if d1[k] == v:
continue
d[k] = (d1[k], v)
else:
d[k] = v
return d
Ok, here goes. Since an explanation was requested.
Start with an empty dictionary, d3, that will be used as the merged
dictionary.
Copy everything from d1 into d3.
Then for each key in d2:
copy the key/value pair into d3 if the key didn't exist in d1.
Otherwise, do the special dupe/tuple logic.
Solution:
def combine_dicts(d1, d2):
d3 = d1.copy() # start by copying the first dict
for k in d2:
if (k in d1):
if d1[k] != d2[k]:
d3[k] = (d1[k], d2[k])
else:
d3[k] = d2[k]
return d3

Python: sum values of dict which keys are values in another dict

Say that we have two dictionaries:
d1={'A':['a','b','c'],'B':['d','e']}
d2={'a':3,'b':1,'c':1,'d':2,'e':0}
And that we need to compute a third dictionary that has the same keys as d1, and for values the sum of the values in d2 that correspond to those keys that are, in turn, values ind1.
Example:
d3={'A':5,'B':2}
where 5 is assigned to A because it is the sum of the values of a,b,c, which are assigned to A in d1.
My attempt:
d3={key:sum(d2[i] for i in d1[j] for j in d1.keys()) for key in d1.keys()}
returns:
NameError: global name 'j' is not defined
Sorry for the trivial question, but what am I missing here?
It's simpler than that if you use dict.items():
d3 = {key: sum(d2[v] for v in val) for key, val in d1.items()}
d3 = {}
for k,v in d1.items():
d3[k] = sum([ d2[x] for x in v ])
d1={'A':['a','b','c'],'B':['d','e']}
d2={'a':3,'b':1,'c':1,'d':2,'e':0}
dict(zip(d1.keys(), map(lambda x:sum(d2.get(i) for i in x[1]), d1.items())))

Python remove dictionary keys which don't occur in separate dictionary

I have two dictionaries, I need to remove the keys from dictionary 1 which don't occur in dictionary 2. This is my attempt:
d1 = {'id1':1,
'id2':1,
'id3':1,
'id4':1}
d2 = {'id1':0,
'id2':0,
'id3':0,
'idnew':0}
for k in (d1.keys()-d2.keys()):
del d1[k]
print (d1)
prints:
{'id1': 1, 'id2': 1, 'id3': 1}
My question is: Is this the fastest/most memory efficient way to do this? or does it construct sets which will take up more memory than required to do something like this
My 2nd attempt:
d1 = {k:v for k,v in d1.items() if k in d2}
filter and dict comprehension might be a good way to go for such a task, although this issue is easy to solve without as well.
filtered_d = {k:d1[k] for k in filter(lambda k: k in d2, d1)}
Dict comprehension can have a perfomance hit when dictionaries a large. You can remove them just iterating over list with for loop:
for key in set(d1) -set(d2):
del d1[key]
or if you know that your dicts will be small, you can use dict comprehension.
d1 = {k: v for k, v in d1.items() if k in d2}
Your solve is good because : the fastest/most memory efficient issues come from type of values and sized .
This can be see and set with a python debugger.

Python 2.7 append values to dictionary

I have 2 dictionaries with identical keys.
d1 = {'Dog':[7,2],'Cat':[5,2]}
d2 = {'Dog':1,'Cat':4}
Is there a good way of combining them so that I can have one dictionary that looks like this?
d = {'Dog':[7,2,1],'Cat':[5,2,4]}
for key, value in d2.iteritems():
if key in d1:
d1[key].append(value)
If one contains lists and the other contains ints, you can do:
d = {key:[d2[key]] + d1[key] for key in d1}

Categories