How to multiply values of matching keys together? - python-3.x

x = {"a": 1, "b": 2, "c": 3}
y = {"b": 4, "c": 5, "d": 6}
for key in x:
if key in y:
a = (x[key])
b = (y[key])
This returns a as 2 3 and b as 4 5. What i'm trying to do is multiply the matching key values together and then add those values together. I am not quite sure how to do this. If you guys could help me out that would be great. Thank you in advanced.

A simple way to do this would be to just keep a running total, e.g.:
total = 0
for key in x:
if key in y:
a = x[key]
b = y[key]
total += a*b
print(total) # 23
But python has powerful comprehensions/generators that can simplify this to:
>>> sum(x[key]*y[key] for key in x if key in y)
23

You can use sum with a generator:
x = {"a": 1, "b": 2, "c": 3}
y = {"b": 4, "c": 5, "d": 6}
sum(x[k] * y[k] for k in set(x) & set(y))
# 23

Related

Full addresses from nested dictionaries

We have data like this
input = {
'a': 3,
'b': {'g': {'l': 12}},
'c': {
'q': 3,
'w': {'v': 3},
'r': 8,
'g': 4
},
'd': 4
}
It is not known in advance how many nesting levels there will be
We need to get the full address to the final value, all points of which are separated by a dot, or another special character
Like this:
a:3
b.g.l: 12
c.q: 3
c.w.v: 3
etc
I tried to solve this problem with a recursive function.
def recursive_parse(data: dict, cache: Optional[list]=None):
if cache is None:
cache = []
for k in data:
cache.append(k)
if not isinstance(data[k], dict):
print(f"{'.'.join(cache) } :{data[k]}")
cache.clear()
else:
recursive_parse(data[k], cache)
But I have problems with "remembering" the previous key of the nested dictionary.
a :3
b.g.l :12
c.q :3
w.v :3
r :8
g :4
d :4
What is the correct algorithm to solve this?
It's probably better to use an explicit stack for this, rather than the Python call stack. Recursion is slow in Python, due to high function call overhead, and the recursion limit is fairly conservative.
def dotted(data):
result = {}
stack = list(data.items())
while stack:
k0, v0 = stack.pop()
if isinstance(v0, dict):
for k1, v1 in v0.items():
item = ".".join([k0, k1]), v1
stack.append(item)
else:
result[k0] = v0
return result
Demo:
>>> data
{'a': 3,
'b': {'g': {'l': 12}},
'c': {'q': 3, 'w': {'v': 3}, 'r': 8, 'g': 4},
'd': 4}
>>> for k, v in reversed(dotted(data).items()):
... print(k, v)
...
a 3
b.g.l 12
c.q 3
c.w.v 3
c.r 8
c.g 4
d 4
Try:
dct = {
"a": 3,
"b": {"g": {"l": 12}},
"c": {"q": 3, "w": {"v": 3}, "r": 8, "g": 4},
"d": 4,
}
def parse(d, path=None):
if path is None:
path = []
if isinstance(d, dict):
for k, v in d.items():
yield from parse(v, path + [k])
else:
yield "{}: {}".format(".".join(path), d)
for p in parse(dct):
print(p)
Prints:
a: 3
b.g.l: 12
c.q: 3
c.w.v: 3
c.r: 8
c.g: 4
d: 4

How to check the values in two dictionaries have the same type?

For example, I have two dictionaries having the same keys:
a = {"a": 1, "b": 2, "c":4.5, "d":[1,2], "e":"string", "f":{"f1":0.0, "f2":1.5}}
b = {"a": 10, "b": 20, "c":3.5, "d":[0,2,4], "e":"q", "f":{"f1":1.0, "f2":0.0}}
and I want to compare the types. My code is something like this:
if type(a["a"]) == type(b["a"]) and type(a["b"]) == type(b["b"]) and type(a["c"]) == type(b["c"]) and type(a["d"]) == type(b["d"]) and type(a["e"]) == type(b["e"]) and type(a["f"]) == type(b["f"]) and type(a["f"]["f1"]) == type(b["f"]["f1"]) and type(a["f"]["f2"]) == type(b["f"]["f2"]):
first_type = type(b["d"][0])
if all( (type(x) is first_type) for x in a["d"] )
#do something
pass
Is there a better way to do it?
You can make a list of the common keys between the dicts:
common_keys = a.keys() & b.keys()
and then iterate over them to check the types:
for k in common_keys:
if type(a[k]) == type(b[k]):
print("Yes, same type! " + k, a[k], b[k])
else:
print("Nope! " + k, a[k], b[k])
and if you wanted to go deeper, check if any of the items are dicts, rinse an repeat
for k in common_keys:
if type(a[k]) == type(b[k]):
print("Yes, same type! " + k, type(a[k]), type(b[k]))
if isinstance(a[k], dict):
ck = a[k].keys() & b[k].keys()
for key in ck:
if type(a[k][key]) == type(b[k][key]):
print("Yes, same type! " + key, type(a[k][key]), type(b[k][key]))
else:
print("Nope!")
else:
print("Nope! " + k, type(a[k]), type(b[k]))
You can use a for loop to iterate through the dicts:
same_types = True
for key in a.keys():
if type(a[key]) != type(b[key]):
same_types = False
break
# if the value is a dict, check nested value types
if type(a[key]) == dict:
for nest_key in a[key].keys():
if type(a[key][nest_key]) != type(b[key][nest_key]):
same_types = False
break
# if the value is a list, check all list elements
# I just simply concat two lists together, you can also refer to
# https://stackoverflow.com/q/35554208/19322223
elif type(a[key]) == list:
first_type = a[key][0]
for elem in a[key] + b[key]:
if type(elem) != first_type:
same_types = False
break
if not same_types:
break
if same_types:
# do something
With the following helper function:
def get_types(obj, items=None):
"""Function that recursively traverses 'obj' and returns
a list of all values and nested values types
"""
if not items:
items = []
if isinstance(obj, dict):
for value in obj.values():
if not isinstance(value, (dict, list, set, tuple)):
items.append(value)
else:
get_types(value, items)
elif isinstance(obj, (list, set, tuple)):
for value in obj:
get_types(value, items)
else:
items.append(obj)
return [type(x) for x in items]
You can compare two dictionaries' values types however deeply nested these are, like this:
if get_types(a) == get_types(b):
print("Each a and b values are of same types")
Since, in your example, a misses one value for d key ([1, 2]) compared to the other dict ([0, 2, 4]), nothing will be printed.
Let's take another example where both dictionaries have the same shape this time, but one value of different type (f2):
a = {"a": 1, "b": [[1, 2], [3, [4]]], "c": {"c1": 0.0, "c2": {"x": "9"}}}
b = {"d": 7, "e": [[2, 1], [5, [7]]], "f": {"f1": 8.9, "f2": {"y": 9}}}
if get_types(a) == get_types(b):
print("Each a and b values are of same types")
Then again, nothing will be printed.
But if you replace 9 by "9" in b["f2"]:
a = {"a": 1, "b": [[1, 2], [3, [4]]], "c": {"c1": 0.0, "c2": {"x": "9"}}}
b = {"d": 7, "e": [[2, 1], [5, [7]]], "f": {"f1": 8.9, "f2": {"y": "9"}}}
if get_types(a) == get_types(b):
print("Each a and b values are of same types")
# Output
# Each a and b values are of same types

How to find N% of key and values from a python dictiobary

I have a python dictionary:-
x = {"a": 1, "b": 2, "c": 3, "d":4, "e": 5, "f": 6}
I want to find only the N% of the dictonary's keys and values returned to me.
For instance, out of this dictionary, I want to fetch 50% of the key,value pairs only.
So my output should be :-
{"a": 1, "b": 2, "c": 3}
Any help ?
First calculate the count which corresponds to given percentage and also make sure it is an integer. You can also use floor or ceil functions to round of to integers. Then you can use enumerate as below
x = {"a": 1, "b": 2, "c": 3, "d":4, "e": 5, "f": 6}
percent = 50
count = int(percent*len(x)/100)
output = {}
for i,key in enumerate(x.keys(),1):
if(i>count):
break
output[key] = x[key]
print(output)
If you want to choice randomly N% of the element in a python dictionary, you can use random model.
import random
x = {"a": 1, "b": 2, "c": 3, "d":4, "e": 5, "f": 6}
percent = 50
count = int(percent*len(x)/100)
# get list of all the keys in the dictionary and convert it to a list
keys = x.keys()
keys = list(keys)
# use random.choices to choice randomly count element from the keys list
new_keys = random.choices(keys, k=count)
output = {}
for key in new_keys:
output[key] = x[key]
print(output)
you will get as output
{'d': 4, 'a': 1, 'c': 3}

Creating new dictionaries using keys from main dict[BEGINNER]

I'm trying to check whether a specific key ends with ":F" or ":M", so i can create new dictionaries called male and female.
d = {'Jane:F': 3, 'Tom:M': 2, 'Jeff:M': 5, 'Mary:F': 3} #initial dict
male = {'Tom': 2, 'Jeff': 5} #required output
female = {'Jane': 3, 'Mary': 3} #required output
You can split the key by : and then check for M and/or F:
d = {'Jane:F': 3, 'Tom:M': 2, 'Jeff:M': 5, 'Mary:F': 3}
male, female = {}, {}
for k, v in d.items():
k, gender = k.split(':')
if gender == 'M':
male[k] = v
else:
female[k] = v
print(male)
print(female)
Prints:
{'Tom': 2, 'Jeff': 5}
{'Jane': 3, 'Mary': 3}
Another version using dict-comprehensions:
male = {k.split(':')[0]: v for k, v in d.items() if k.endswith(':M')}
female = {k.split(':')[0]: v for k, v in d.items() if k.endswith(':F')}

Adding values of one dictionary if the keys match the keys of the other dictionary

I am new to python. I'd like to ask for your assistance regarding operations with dictionaries. I guess, the question is a bit basic. But, I'm kinda stuck.
I need to get the total of values in dict2 corresponding the "JJ" values in dict1. Since "JJ" in dict1 is associated with keys "A" and "B", the corresponding values in dict2 are 30 and 100, which sums to 130
Thank you!
Rn
My code (I'm getting the sum of all values in dict2=145 after step 2 instead of just A+B=130)
dict1 = {"A":"JJ", "B":"JJ", "C":"X"}
dict2 = {"A":30, "B":100, "C":15}
dict3=dict()
for (kk, vv) in dict1.items():
ref_val="JJ"
if vv == ref_val:
dict3[kk] = vv
print(dict3)
total_points=0
for (kk, vv) in dict2.items():
for (kk, vv) in dict3.items():
total_points = sum(vv for vv in dict2.values())
print(total_points)
I hope I understood the question correctly.
I so, this should work:
dict1 = {"A": "JJ", "B": "JJ", "C": "X"}
dict2 = {"A": 30, "B": 100, "C": 15}
keys = set(k for k, v in dict1.items() if v == "JJ")
total_points = sum(dict2.get(k, 0) for k in keys)
print(total_points)
keys: using list comprehension the keys having value equal to JJ are selected
total_points: the values corresponding to those keys are fetch from dict2 and summed on the fly. If a key from keys is not present in dict2 (which is not the case, btw) 0 (zero) is fetched instead (so it won't affect the sum)
I like the other answer but I would probably solve this problem a little more generically:
from collections import defaultdict
dict1 = {"A": "JJ", "B": "JJ", "C": "X"}
dict2 = {"A": 30, "B": 100, "C": 15}
val_to_keys = defaultdict(list)
for key, val in dict1.items():
val_to_keys[val].append(dict2.get(key, 0))
# Note that now val_to_keys contains:
# {'JJ': [30, 100], 'X': [15]}
if 'JJ' in val_to_keys:
print(sum(val_to_keys['JJ'])) # 130
# or you can one line the print
print(sum(val_to_keys.get('JJ', []))) # 130
This way you can only need to iterate over the dict1 once and you can pull out any value you want.
Note that if all you care about is the sums then it can be even more efficient by calculating the sum during the initial iteration. (I use a normal dict instead of a defaultdict here just to show how you can do it both with regular dictionaries and defaultdicts).
dict1 = {"A": "JJ", "B": "JJ", "C": "X"}
dict2 = {"A": 30, "B": 100, "C": 15}
val_to_keys = {}
for key, val in dict1.items():
val_to_keys[val] = val_to_keys.get(val, 0) + dict2.get(key, 0)
# Note that now val_to_keys contains:
# {'JJ': 130, 'X': 15}
if 'JJ' in val_to_keys:
print(val_to_keys['JJ']) # 130

Resources