Compare two excel file - python

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

Related

Search keys and read from multiple dictionaries

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}

Watching a counter, tally total and counting missed counts

I am attempting to create a piece of code that will watch a counter with an output something like:
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
I want the code to be able to tally the total and tell me how many counts are missed for example if this happened:
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24, 25, 26, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,1,2]
I would get a total of 92 still, but get feedback that 8 are missing.
I have gotten very close with the following code:
Blk_Tot = 0
CBN = 0
LBN = 0
x = 0
y = 0
z = 0
MissedBlocks = 0
for i in range(len(a1)):
CBN = a1[i]
if CBN - LBN <= 0:
if LBN == 30:
y = 30 - abs(CBN - LBN)
elif LBN < 30:
z = 30 - LBN
y = 30 - abs(CBN - LBN) + z
print(z)
Blk_Tot = Blk_Tot + y
else:
x = CBN - LBN
Blk_Tot = Blk_Tot + x
if x > 1:
MissedBlocks = MissedBlocks - 1 + x
LBN = CBN
print(Blk_Tot)
print(MissedBlocks)
If I delete anywhere between 1 and 30 it works perfectly, however if I delete across 30, say 29,30,1,2 it breaks.I don't expect it to be able to miss 30 in a row and still be able to come up with a proper total however.
Anyone have any ideas on how this might be achieved? I feel like I am missing an obvious answer :D
Sorry I think I was unclear, a1 is a counter coming from an external device that counts from 1 to 30 and then wraps around to 1 again. Each count is actually part of a message to show that the message was received; so say 1 2 4, I know that the 3rd message is missing. What I am trying to do is found out the total that should have been recieved and how many are missing from the count.
Update after an idea from the posts below, another method of doing this maybe:
Input:
123456
List[1,2,3,4,5,6]
1.Check first input to see which part of the list it is in and start from there (in case we don't start from zero)
2.every time an input is received check if that matches the next value in the array
3.if not then how many steps does it take to find that value
You don't need to keep track if you past the 30 line.
Just compare with the ideal sequence and count the missing numbers.
No knowledge if parts missing at the end.
No knowledge if more than 30 parts are missing in a block.
from itertools import cycle
def idealSeqGen():
for i in cycle(range(1,31)):
yield(i)
def receivedSeqGen():
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,
5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1,2]
for i in a1:
yield(i)
receivedSeq = receivedSeqGen()
idealSeq = idealSeqGen()
missing = 0
ideal = next(idealSeq)
try:
while True:
received = next(receivedSeq)
while received != ideal:
missing += 1
ideal = next(idealSeq)
ideal = next(idealSeq)
except StopIteration:
pass
print (f'There are {missing} items missing')
Edit
The loop part can be a little bit simpler
missing = 0
try:
while True:
ideal = next(idealSeq)
received = next(receivedSeq)
while received != ideal:
missing += 1
ideal = next(idealSeq)
except StopIteration:
pass
print (f'There are {missing} items missing')
In general, if you want to count the number of differences between two lists, you can easily use a dictionary. The other answer would also work, but it is highly inefficient for even slightly larger lists.
def counter(lst):
# create a dictionary with count of each element
d = {}
for i in lst:
if d.get(i, None):
d[i] += 1
else:
d[i] = 1
return d
def compare(d1, d2):
# d1 and d2 are dictionaries
ans = 0
for i in d1.values():
if d2.get(i, None):
# comapares the common values in both lists
ans += abs(d1[i]-d2[i])
d2[i] = 0
else:
#for elements only in the first list
ans += d1[i]
for i in d2.values():
# for elements only in the second list
if d2[i]>0:
ans += d2[i]
return ans
l1 = [...]
l2 = [...]
print(compare(counter(l1), counter(l2)))
New code to check for missing elements from a repeating sequence pattern
Now that I have understood your question more clearly, here's the code. The assumption in this code is the list will always be in ascending order from 1 thru 30 and then repeats again from 1. There can be missing elements between 1 and 30 but the order will always be in ascending order between 1 and 30.
If the source data is as shown in list a1, then the code will result in 8 missing elements.
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,
5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1,2]
a2 = a1.copy()
c = 1
missing = 0
while a2:
if a2[0] == c:
c+=1
a2.pop(0)
elif a2[0] > c:
missing +=1
c+=1
elif a2[0] < c:
missing += 31-c
c = 1
if c == 31: c=1
print (f'There are {missing} items missing in the list')
The output of this will be:
There are 8 items missing in the list
Let me know if this addresses your question
earlier code to compare two lists
You cannot use set as the items are repeated. So you need to sort them and find out how many times each element is in both lists. The difference will give you the missing counts. You may have an element in a1 but not in a2 or vice versa. So finding out the absolute count of missing items will give you the results.
I will update the response with better variables in my next update.
Here's how I did it:
code with comments:
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
a2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,
5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,1,2]
#step 1: Find out which list is longer. We will use that as the master list
if len(a1) > len(a2):
master_list = a1.copy()
second_list = a2.copy()
else:
master_list = a2.copy()
second_list = a1.copy()
#step 2: We must sort both master and second list
# so we can compare against each other
master_list.sort()
second_list.sort()
#set the counter to zero
missing = 0
#iterate through the master list and find all values in master against second list
#for each iteration, remove the value in master[0] from both master and second list
#when you have iterated through the full list, you will get an empty master_list
#this will help you to use while statement to iterate until master_list is empty
while master_list:
#pick the first element of master list to search for
x = master_list[0]
#count the number of times master_list[0] is found in both master and second list
a_count = master_list.count(x)
b_count = second_list.count(x)
#absolute difference of both gives you how many are missing from each other
#master may have 4 occurrences and second may have 2 occurrences. abs diff is 2
#master may have 2 occurrences and second may have 5 occurrences. abs diff is 3
missing += abs(a_count - b_count)
#now remove all occurrences of master_list[0] from both master and second list
master_list = [i for i in master_list if i != x]
second_list = [i for i in second_list if i != x]
#iterate until master_list is empty
#you may end up with a few items in second_list that are not found in master list
#add them to the missing items list
#thats your absolute total of all missing items between lists a1 and a2
#if you want to know the difference between the bigger list and shorter one,
#then don't add the missing items from second list
missing += len(second_list)
#now print the count of missig elements between the two lists
print ('Total number of missing elements are:', missing)
The output from this is:
Total number of missing elements are: 7
If you want to find out which elements are missing, then you need to add a few more lines of code.
In the above example, elements 27,28,29,30, 4, 5 are missing from a2 and 31 from a1. So total number of missing elements is 7.
code without comments:
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
a2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,
5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,1,2]
if len(a1) > len(a2):
master_list = a1.copy()
second_list = a2.copy()
else:
master_list = a2.copy()
second_list = a1.copy()
master_list.sort()
second_list.sort()
missing = 0
while master_list:
x = master_list[0]
a_count = master_list.count(x)
b_count = second_list.count(x)
missing += abs(a_count - b_count)
master_list = [i for i in master_list if i != x]
second_list = [i for i in second_list if i != x]
missing += len(second_list)
print ('Total number of missing elements are:', missing)

Dictionary values and list values within a function

I have a dictionary with product names and prices:
products = {'a': 2, 'b': 3, 'c': 4, 'd': 5, 'e': 6, 'f': 7, 'g': 8}
And a list with amounts of each product:
amounts = [3, 0, 5, 1, 3, 2, 0]
I want to get an output shown there total price of that order.
Not using functions I seem to get it right:
products = {'a': 2, 'b': 3, 'c': 4, 'd': 5, 'e': 6, 'f': 7, 'g': 8}
amounts = [3, 0, 5, 1, 3, 2, 0]
res_list = []
order = []
for value in products.values():
res_list.append(value)
for i in range(0, len(res_list)):
order.append(amounts[i] * res_list[i])
total = sum(order)
print(res_list)
print(order) #this line and the one above are not really necessary
print(total)
Output : 63
But when I try using this code within a function I am having some problems. this is what I have tried:
products = {'a': 2, 'b': 3, 'c': 4, 'd': 5, 'e': 6, 'f': 7, 'g': 8}
amounts = [3, 0, 5, 1, 3, 2, 0]
#order = []
def order(prod):
res_list = []
for value in prod.values():
res_list.append(value)
return res_list
prices = order(products)
print(prices)
def order1(prices):
order =[]
for i in range(0, len(prices)):
order.append(amounts[i] * prices[i])
total = sum(order)
return total
print(order1(prices))
Not working the way it is intended.
Thanks for all the help I am learning.
The immediate problem is that your lines:
total = sum(order)
return total
are indented too much, so that they are inside the for loop. Outside of a function, the bug does not matter too much, because all that happens is that the total is recalculated on every iteration but the final value is the one that is used. But inside the function, what will happen is that it will return on the first iteration.
Reducing the indentation so that it is outside the for loop will fix this.
def order1(prices):
order =[]
for i in range(0, len(prices)):
order.append(amounts[i] * prices[i])
total = sum(order)
return total
However, separate from that, you are relying on the order within the dictionary, which is only guaranteed for Python 3.7 and more recent. If you want to allow the code to be run reliably on earlier versions of Python, you can use an OrderedDict.
from collections import OrderedDict
products = OrderedDict([('a', 2), ('b', 3), ('c', 4), ('d', 5),
('e', 6), ('f', 7), ('g', 8)])
Incidentally, your order function is unnecessary. If you want to convert products.values() (a dictionary values iterator) to a list, just use:
prices = list(products.values())
Also, in order1 it is unnecessary to build up an order list and sum it - you could use:
total = 0
for i in range(0, len(prices)):
total += amounts[i] * prices[i]
That is probably enough to be getting on with for now, but if you wish to make a further refinement, then look up about how zip is used, and think how it could be used with your loop over amounts and prices.
Just zip products.values() and amounts, find the product of each pair, and then finally sum the result
>>> products = {'a': 2, 'b': 3, 'c': 4, 'd': 5, 'e': 6, 'f': 7, 'g': 8}
>>> amounts = [3, 0, 5, 1, 3, 2, 0]
>>>
>>> sum(i*j for i,j in zip(products.values(), amounts))
63
You can do this.
products = {'a': 2, 'b': 3, 'c': 4, 'd': 5, 'e': 6, 'f': 7, 'g': 8}
amounts = [3, 0, 5, 1, 3, 2, 0]
def order(products, amounts):
res_list = []
order = []
for value in products.values():
res_list.append(value)
for i in range(0, len(res_list)):
order.append(amounts[i] * res_list[i])
total = sum(order)
print(res_list)
print(order) #this line and the one above are not really necessary
print(total)
return(total)
order(products, amounts)
You don't really need to iterate twice assuming that the amount of items in products and in amounts is the same.
products = {'a': 2, 'b': 3, 'c': 4, 'd': 5, 'e': 6, 'f': 7, 'g': 8}
amounts = [3, 0, 5, 1, 3, 2, 0]
def order(products: dict, amounts: list):
total = 0
for idx, (_key, val) in enumerate(products.items()):
total = total + amounts[idx] * val
return total
print(order(products, amounts))
Note: The order of the items in the dictionary is not guaranteed, you might want to look into different data structures that link together products and amounts in a better way, i.e.:
products = {'a': 2, 'b': 3, 'c': 4, 'd': 5, 'e': 6, 'f': 7, 'g': 8}
amounts = {'a': 3, 'b': 0, 'c': 5, 'd': 1, 'e': 3, 'f': 2, 'g': 0}
In this way you could do this:
def order(products: dict, amounts: dict):
total = 0
for key, val in products.items():
total = total + val * amounts[key]
return total
print(order(products, amounts))
Once we're at it, let's get fancy with numpy, since in the end, you just want the dot product prices x amounts:
import numpy as np
total = np.dot(list(products.values()), amounts)
63
But seriously, I'd strictly use either lists or dicts for both datasets, not mix them up, since that can seriously cause problems with order syncronisation between them, even if you are on Python 3.7 with the changes made there as mentioned.

Problem with finding the GCD for the elements of a list using max and lambda

So this is my code, and i've used a lambda function as a key to find the max of the result list, but it wont work. I don't want to use any other built in functions or methods, just modify the KEY if possible. The result for this given list should be 6, but my code returns 1!
def find_gcd(my_list):
result = []
for item in my_list:
for divs in range(1, item+1):
if item % divs ==0:
result.append(divs)
result.sort()
x = max(result, key = lambda x : result.count(x))
return x
print(find_gcd([12, 24, 6, 18]))
change your key to this:
max(result, key = lambda x : (result.count(x), x))
your result in your scenario (find_gcd([12, 24, 6, 18])) is this:
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 6, 6, 6, 6, 8, 9, 12, 12, 18, 24]
we have same number of 1s , 2s ,3s and 6s in the result as you see.(both have 4 occurrence). but we want the greatest one.
NOTE: We can use two element tuple for these problem. the first element for number of occurrence (e.g: 4 occurrence for number 1) and the second one is the number itself. between (4, 1) and (4, 6), the (4, 6) is greater and it will return.

How to get key values from default dictionary in Python?

I have a default dictionary with name df:
defaultdict(<type 'int'>, {u'DE': 1, u'WV': 1, u'HI': 1, u'WY': 1, u'NH': 2, u'NJ': 1, u'NM': 1, u'TX': 1, u'LA': 1, u'NC': 1, u'NE': 1, u'TN': 1, u'RI': 1, u'VA': 1, u'CO': 1, u'AK': 1, u'AR': 1, u'IL': 1, u'GA': 1, u'IA': 1, u'MA': 1, u'ID': 1, u'ME': 1, u'OK': 2, u'MN': 1, u'MI': 1, u'KS': 1, u'MT': 1, u'MS': 1, u'SC': 2, u'KY': 1, u'OR': 1, u'SD': 1})
how do I get the keys of this dictionary whose values are more than 1.
If I do [df[val] for val in df if df[val]>1]
I get the output as [2, 2, 2]
If I print [df.keys() for val in df if df[val]>1] Still I donot get the key values, I need the keys that has values more than 2 like this ['SC', 'OK', 'NH']
How do I do that??
Reading from a dictionary created using defaultdict() is the same as a normal dict.
To get the keys which have values > 1, you would do:
my_dict = defaultdict(...)
print [key for key, value in my_dict.iteritems() if value > 1]
If you're using Python 3 then it's my_dict.items().
We can use list compression method.
>>> from collections import defaultdict
>>> d = defaultdict(int)
>>> d['HI'] = 1
>>> d['NH'] = 2
>>> d['WY'] = 1
>>> d['OK'] = 2
>>> [i[0] for i in d.items() if i[1]>1]
['NH', 'OK']

Categories