Search keys and read from multiple dictionaries - python

Several dictionaries containing different keys and values.
By looping a list of keys, I want to return their values in the dictionaries (when the key is available), and sum them.
The problem is, some keys are not available in all the dictionaries.
I need to come up with different IF statements, which look clumsy. Especially when there are more dictionaries came in, it became very difficult.
What is the different smart way to do so?
dict_1 = {"Mike": 1, "Lilly": 2, "David": 3}
dict_2 = {"Mike": 4, "Peter": 5, "Kate": 6}
dict_3 = {"Mike": 7, "Lilly": 8, "Jack": 9}
for each in ["Mike", "Lilly", "David"]:
if each in list(dict_1.keys()) and each in list(dict_2.keys()) and each in list(dict_3.keys()):
print (each, dict_1[each] * 1 + dict_2[each] * 2 + dict_3[each] * 3)
if each in list(dict_1.keys()) and each in list(dict_2.keys()):
print (each, dict_1[each] * 1 + dict_2[each] * 2)
if each in list(dict_2.keys()) and each in list(dict_3.keys()):
print (dict_2[each] * 2 + dict_3[each] * 3)
if each in list(dict_1.keys()) and each in list(dict_3.keys()):
print (each, dict_1[each] * 1 + dict_3[each] * 3)

You can pass 0 if the key is not found.
for each in ["Mike", "Lilly", "David"]:
print(each, dict_1.get(each, 0)*1 + dict_2.get(each, 0)*2 + dict_3.get(each, 0)*3)
Output:
Mike 30
Lilly 26
David 3

Since the dicts are named with sequential numbers, a more streamlined approach would be to put them in a list and use enumerate to generate the factors that you apply to the values in each dict when you sum them by key:
records = [
{"Mike": 1, "Lilly": 2, "David": 3},
{"Mike": 4, "Peter": 5, "Kate": 6},
{"Mike": 7, "Lilly": 8, "Jack": 9}
]
for name in "Mike", "Lilly", "David":
print(name, sum(factor * record.get(name, 0) for factor, record in enumerate(records, 1)))
This outputs:
Mike 30
Lilly 26
David 3

(Given that you are checking the sum of total occurances of elements in different dictictionaries) I do think collections.Counter is a better way of doing your task:
https://docs.python.org/3/library/collections.html#collections.Counter
Examples
from collections import Counter
counter1 = Counter({"Mike": 1, "Lilly": 2, "David": 3}) #counter object from a mapping
counter2 = Counter({"Mike": 4, "Peter": 5, "Kate": 6})
counter3 = Counter({"Mike": 7, "Lilly": 8, "Jack": 9})
countertotal = counter1+counter2+counter2+counter3+counter3+counter3
>>>countertotal
Counter({'Mike': 30,
'Lilly': 26,
'David': 3,
'Peter': 10,
'Kate': 12,
'Jack': 27})
Count of element occurrences can be directly assessed:
for each in ["Mike", "Lilly", "David"]:
print(countertotal[each])
30
26
3
Checking the existence of elements do not throw an error:
for each in ["Ada", "Albert", "Adrian"]:
print(countertotal[each])
0
0
0

You can check if key is in dictionary before you attempt to access it.
dict_list = [
{"Mike": 1, "Lilly": 2, "David": 3},
{"Mike": 4, "Peter": 5, "Kate": 6},
{"Mike": 7, "Lilly": 8, "Jack": 9},
]
dict_res = {"Mike": 0, "Lilly": 0, "David": 0}
#loop through each of the names you want
for key in dict_res.items():
x = 1
#loop through each of your dictionaries
for dict in dict_list:
if key in dict:
# multiply by dictionary number and add to result value
dict_res[key] += dict[key] * x
x += 1
print(dict_res)
Output: {'Mike': 30, 'Lilly': 26, 'David': 3}

Related

Python Find permutable list in a dict list

Given
listOfDict = [{'ref': 1, 'a': 1, 'b': 2, 'c': 3},
{'ref': 2, 'a': 4, 'b': 5, 'c': 6},
{'ref': 3, 'a': 7, 'b': 8, 'c': 9}]
Lets' consider a list of permutable integer
[7,8,9]=[7,9,8]=[8,7,9]=[8,9,7]=[9,7,8]=[9,8,7] # (3!)
Each of this list has a unique mapping ref, so how given for (8,7,9) can I get ref=3 ?
Also in real case I might until 10 (a,b,c,d,e,f,g,h,i,j)...
You can generate a dictionary that maps the values as frozenset to the value of ref:
listOfDict = [{'ref': 1, 'a': 1, 'b': 2, 'c': 3},
{'ref': 2, 'a': 4, 'b': 5, 'c': 6},
{'ref': 3, 'a': 7, 'b': 8, 'c': 9}]
keys = ['a', 'b', 'c']
out = {frozenset(d[k] for k in keys): d['ref'] for d in listOfDict}
# {frozenset({1, 2, 3}): 1,
# frozenset({4, 5, 6}): 2,
# frozenset({7, 8, 9}): 3}
example:
check = frozenset((8,7,9))
out[check]
# 3
but I don't know in advance the name of the other keys!
Then use this approach:
out = {}
for d in listOfDict:
d2 = d.copy() # this is to avoid modifying the original object
out[frozenset(d2.values())] = d2.pop('ref')
out
or as a comprehension:
out = dict(((d2:=d.copy()).pop('ref'), frozenset(d2.values()))[::-1]
for d in listOfDict)
Here is a commented solution to your problem. The idea is to compare the sorted list of the values in a, b, c etc with the sorted values in list_of_ints. The sorted values will be the same for all permutations of a given set of numbers.
def get_ref(list_of_ints):
# Loop through dictionaries in listOfDict.
for dictionary in listOfDict:
# Get list of values in each dictionary.
vals = [dictionary[key] for key in dictionary if key != "ref"]
if sorted(vals) == sorted(list_of_ints):
# If sorted values are equal to sorted list of ints, return ref.
return dictionary["ref"])
By the way, I believe it would be cleaner to structure this data as a dict of dicts in the following way:
dicts = {
1: {'a': 1, 'b': 2, 'c': 3},
2: {'a': 4, 'b': 5, 'c': 6},
3: {'a': 7, 'b': 8, 'c': 9}
}
The code would then be:
def get_ref(list_of_ints):
for ref, dictionary in dicts.items():
if sorted(dictionary.values()) == sorted(list_of_ints):
return ref
Assuming that all integers in the permutations are unique, the code can be simplified further using sets instead of sorted lists.
Since its a list of dict I can call each dict as it self by using for loop
and record the first number on ref
for i in listOfDict:
ref_num=i["ref"]
and to turn dictunary to list we simply use:
z=list(i.values())
then the last step is to find if its the same input list if so we print/return the ref number
if z[1:]==InputList:
return ref_num
and the code should be like this:
listOfDict = [
{"ref": 1,
"a": 1,
"b": 2,
"c": 3},
{"ref": 2,
"a": 4,
"b": 5,
"c": 6},
{"ref": 3,
"a": 7,
"b": 8,
"c": 9},]
def find_ref_Num(InputList):
for i in listOfDict:
ref_num=i["ref"]
z=list(i.values())
if z[1:]==InputList:
return ref_num
print ("your ref number is: "+str(find_ref_Num([7,8,9])))

create leaf dictionary form parent dictionary

There is a dictionary say d , let n > 0
d = {
'leaf1': 1,
'leaf2': 2,
'leaf3': 3,
'leaf4': 4,
'leaf5': 5,
'leaf6': 6
}
I want to create a list of dictionary (say b) taking n items from d
then when n = 1,
b = [{'leaf1': 1},
{'leaf2': 2},
{'leaf3': 3},
{'leaf4': 4},
{'leaf5': 5},
{'leaf6': 6}]
when n = 2, b is
b = [{'leaf1': 1, 'leaf2': 2 },
{'leaf2': 2, 'leaf3': 3},
{'leaf3': 3,'leaf4': 4},
{'leaf4': 4,'leaf5': 5},
{'leaf5': 5,'leaf6': 6},
{'leaf6': 6,'leaf1': 1}]
when n = 3, b will be
b = {'leaf1': 1, 'leaf2': 2 , 'leaf3': 3},
{'leaf2': 2, 'leaf3': 3,'leaf4': 4},
{'leaf3': 3,'leaf4': 4,'leaf5': 5},
{'leaf4': 4,'leaf5': 5,'leaf6': 6},
{'leaf5': 5,'leaf6': 6,'leaf1': 1},
{'leaf6': 6,'leaf1': 1,'leaf2': 2}]
To create a list of dictionary with n elements at a time, we can first loop in len(d.keys()) i.e total no of elements in dictionary, then loop through the indices that we have to add in list element. As the index may become greater than length of d.keys(), so I have added a check in the loop, we can reduce index from len(d.keys()) to start from 0.
def createLeafDictionary(d, n):
array = []
for i in range(len(d.keys())):
leaf = {}
keyList = list(d.keys())
for j in range(i, i+n):
if j >= len(d.keys()):
j = j - len(d.keys())
leaf[keyList[j]] = d[keyList[j]]
array.append(leaf)
return array
keyList variable I have used to create a list of dictionary keys, we can access dictionary values with help of it.

Nesting dictionary algorithm

Suppose I have the following dictionary:
{'a': 0, 'b': 1, 'c': 2, 'c.1': 3, 'd': 4, 'd.1': 5, 'd.1.2': 6}
I wish to write an algorithm which outputs the following:
{
"a": 0,
"b": 1,
"c": {
"c": 2,
"c.1": 3
},
"d":{
"d": 4,
"d.1": {
"d.1": 5,
"d.1.2": 6
}
}
}
Note how the names are repeated inside the dictionary. And some have variable level of nesting (eg. "d").
I was wondering how you would go about doing this, or if there is a python library for this? I know you'd have to use recursion for something like this, but my recursion skills are quite poor. Any thoughts would be highly appreciated.
You can use a recursive function for this or just a loop. The tricky part is wrapping existing values into dictionaries if further child nodes have to be added below them.
def nested(d):
res = {}
for key, val in d.items():
t = res
# descend deeper into the nested dict
for x in [key[:i] for i, c in enumerate(key) if c == "."]:
if x in t and not isinstance(t[x], dict):
# wrap leaf value into another dict
t[x] = {x: t[x]}
t = t.setdefault(x, {})
# add actual key to nested dict
if key in t:
# already exists, go one level deeper
t[key][key] = val
else:
t[key] = val
return res
Your example:
d = {'a': 0, 'b': 1, 'c': 2, 'c.1': 3, 'd': 4, 'd.1': 5, 'd.1.2': 6}
print(nested(d))
# {'a': 0,
# 'b': 1,
# 'c': {'c': 2, 'c.1': 3},
# 'd': {'d': 4, 'd.1': {'d.1': 5, 'd.1.2': 6}}}
Nesting dictionary algorithm ...
how you would go about doing this,
sort the dictionary items
group the result by index 0 of the keys (first item in the tuples)
iterate over the groups
if there are is than one item in a group make a key for the group and add the group items as the values.
Slightly shorter recursion approach with collections.defaultdict:
from collections import defaultdict
data = {'a': 0, 'b': 1, 'c': 2, 'c.1': 3, 'd': 4, 'd.1': 5, 'd.1.2': 6}
def group(d, p = []):
_d, r = defaultdict(list), {}
for n, [a, *b], c in d:
_d[a].append((n, b, c))
for a, b in _d.items():
if (k:=[i for i in b if i[1]]):
r['.'.join(p+[a])] = {**{i[0]:i[-1] for i in b if not i[1]}, **group(k, p+[a])}
else:
r[b[0][0]] = b[0][-1]
return r
print(group([(a, a.split('.'), b) for a, b in data.items()]))
Output:
{'a': 0, 'b': 1, 'c': {'c': 2, 'c.1': 3}, 'd': {'d': 4, 'd.1': {'d.1': 5, 'd.1.2': 6}}}

Compare two excel file

I would like to compare 2 dictionary that retrieve the data from an excel file and I would like for each user to compare his number of absence in between the 2 dictionary and return a message with the name of the user for whom the number of absence will not be equal in the 2 dictionary.
{"jazi": 1, "juge": 1, "juha": 9, "lebe": 4}
{"jazi": 3, "juge": 7, "juha": 5, "lebe": 4}
Like this and the function should return for this example :"" "jazi" not equal ""
I show you my code :
for row in range(1,253):
id2.append(feuille_2.cell_value(row, 2))
absence2.append(float(feuille_2.cell_value(row, 9)))
result = {}
for name in set(id2):
result[name] = 0
for i in range(len(id2)):
hours = float(absence2[i])
name = id2[i]
result[name] += hours
print(result)
and the other :
for row in range(1,360):
id.append(feuille_1.cell_value(row, 2))
absence2.append(float(feuille_1.cell_value(row, 9)))
result2 = {}
for name2 in set(id):
result[name2] = 0
for i in range(len(id)):
hours2 = float(absence[i])
name2 = id[i]
result[name2] += hours2
print(result2)
I just have one more question if in one of my dictionary i have more value than the other can i still compare both dictionary or i have to change my code ?
Like this :
dict1={"jazi": 1, "juge": 1, "juha": 9, "lebe": 4}
dict2={"jazi": 3, "juge": 4, "juha": 1, "lebe": 4, "aba":7, "meze":9}
code:
dict1={"jazi": 1, "juge": 1, "juha": 9, "lebe": 4}
dict2={"jazi": 3, "juge": 7, "juha": 5, "lebe": 4}
for key in dict1:
if dict1[key]!=dict2[key]:
print("%s not equal"% (key))
output:
jazi not equal
juge not equal
juha not equal
I hope to understand your question

merge two lists of dictionaries without ids in Python

I have two lists of dicts like this :
list1 =[{doc:1,pos_ini:5,pos_fin:10},{doc:1,pos_ini:7,pos_fin:12},{doc:2,pos_ini:5,pos_fin:10},**{doc:7,pos_ini:5,pos_fin:10}**]
list2 =
[{doc:1,pos_ini:5,pos_fin:10},**{doc:1,pos_ini:6,pos_fin:7}**,{doc:1,pos_ini:7,pos_fin:12},{doc:2,pos_ini:5,pos_fin:10},**{doc:2,pos_ini:25,pos_fin:30}**]
list2 has two elements that list1 does not have and list1 has one element that list2 does not have.
I need a list_result with all the elements merged :
list_result =[{doc:1,pos_ini:5,pos_fin:10},**{doc:1,pos_ini:6,pos_fin:7}**,{doc:1,pos_ini:7,pos_fin:12},{doc:2,pos_ini:5,pos_fin:10},
**{doc:2,pos_ini:25,pos_fin:30}**,**{doc:7,pos_ini:5,pos_fin:10}**]
Whats the best way to do that in Python ? thanks!
In Python there is the builtin set collection that is perfect for this. The problem is that sets need hashable elements so you must convert the dict to a set of tuples:
[dict(items) for items in set(tuple(sorted(d.items())) for d in (list1 + list2))]
You can use frozenset() to hash each dictionaries items() to a dictionary, then simply take the assigned values:
list({frozenset(x.items()): x for x in list1 + list2}.values())
Or using map() applied to a set comprehension:
list(map(dict, {frozenset(x.items()) for x in list1 + list2}))
Or even using just a list comprehension:
[dict(d) for d in {frozenset(x.items()) for x in list1 + list2}]
Which will give an unordered result:
[{'doc': 1, 'pos_fin': 10, 'pos_ini': 5},
{'doc': 1, 'pos_fin': 12, 'pos_ini': 7},
{'doc': 2, 'pos_fin': 10, 'pos_ini': 5},
{'doc': 7, 'pos_fin': 10, 'pos_ini': 5},
{'doc': 1, 'pos_fin': 7, 'pos_ini': 6},
{'doc': 2, 'pos_fin': 30, 'pos_ini': 25}]
Note: If order is needed, you can use a collections.OrderedDict() instead here:
from collections import OrderedDict
list(OrderedDict((frozenset(x.items()), x) for x in list1 + list2).values())
Which gives this ordered result:
[{'doc': 1, 'pos_fin': 10, 'pos_ini': 5},
{'doc': 1, 'pos_fin': 12, 'pos_ini': 7},
{'doc': 2, 'pos_fin': 10, 'pos_ini': 5},
{'doc': 7, 'pos_fin': 10, 'pos_ini': 5},
{'doc': 1, 'pos_fin': 7, 'pos_ini': 6},
{'doc': 2, 'pos_fin': 30, 'pos_ini': 25}]
You can create a set out of these values, instead of the dictionaries it would require to be converted into a hashable object like tuple:
unique_list = set(tuple(dictionary.items())) for dictionary in list1 + list2)
and then can be converted back to dictionaries and list format again:
l = []
for item in unique_list:
l.append(dict(item))
Something like above should work.

Categories