Find keys of dictionary that sum to 6 - python

I'm having trouble accessing multiple values in a dictionary. Let's say I have this dictionary:
{'1': 0, '2': 1, '3': 2, '4': 3, '5': 4, '6': 5}
I want to find two keys that sum to 6 and display their values. Here, the keys 4 and 2 add to 6, so the 2 values are 3 and 1.
Where do I start? This is the code I have so far:
for key in dico:
if sum(key + key) == 6:
print(f"Numbers # {key:dico} have a sum of 6")

No need for extra loops (or itertools), they will only slow your program down. You already know what the other index needs to be (because you can subtract the index from 6), so just check if that index exists:
dct = {'1': 0, '2': 1, '3': 2, '4': 3, '5': 4, '6': 5}
for i, key in enumerate(dct):
if i + 2 > len(dct)/2:
break
matchIndex = str(6 - int(key))
if dct.get(matchIndex) is not None:
print(f'Keys {key} and {matchIndex} have values {dct[key]} and {dct[matchIndex]}')
This approach has a O(n/2) time complexity, while the other answer has O(n^2) time complexity.
When I tested this approach with timeit, it took 1.72 seconds to run this answer one million times, but the itertools answer took 5.83 secondss.

You will need to compare each of the dictionary keys with the rest of the other keys. You can use itertools for this.
As you mention you would like to print the value of each of the keys you have in your dictionary, it would be something like this:
import itertools
dico = {'1': 0, '2': 1, '3': 2, '4': 3, '5': 4, '6': 5}
for a, b in itertools.combinations(dico.keys(), 2):
if int(a) + int(b) == 6:
print(f"{dico[a]} - {dico[b]}")

You need two loops for that.
Also, have in mind that there is more than one answer to that problem
a = {'1': 0, '2': 1, '3': 2, '4': 3, '5': 4, '6': 5}
results = list()
for key_1 in a.keys():
for key_2 in a.keys():
if key_1 != key_2:
if a[key_1] + a[key_2] == 6:
if a[key_1] < a[key_2]:
results.append((key_1, key_2))
print(results)

Related

Python, how to find patterns of different length and to sum the number of match

I have a list like that:hg = [['A1'], ['A1b'], ['A1b1a1a2a1a~'], ['BT'], ['CF'], ['CT'], ['F'], ['GHIJK'], ['I'], ['I1a2a1a1d2a1a~'], ['I2'], ['I2~'], ['I2a'], ['I2a1'], ['I2a1a'], ['I2a1a2'], ['I2a1a2~'], ['IJ'], ['IJK'], ['L1a2']]
For example, if we look at :['A1'] ['A1b'] ['A1b1a1a2a1a~']
I want to count how many time the pattern 'A1','A1b' and 'A1b1a1a2a1a~' occurs.
Basically, A1 appears 3 times (A1 itself, A1 in A1b and A1 in A1b1a1a2a1a) and A1b two times (A1b itself and A1b in A1b1a1a2a1a) and A1b1a1a2a1a one time. Obviously, I want to do that for the entire list.
However, if in the list we have for example E1b1a1, I don't want to count a match of A1 in E1b1a1.
So what I did is:
dic_test = {}
for i in hg:
for j in hg:
if ''.join(i) in ''.join(j):
if ''.join(i) not in dic_test.keys():
dic_test[''.join(i)]=1
else:
dic_test[''.join(i)]+=1
print (dic_test)
output:{'A1': 3, 'A1b': 2, 'A1b1a1a2a1a~': 1, 'BT': 1, 'CF': 1, 'CT': 1, 'F': 2, 'GHIJK': 1, 'I': 12, 'I1a2a1a1d2a1a~': 1, 'I2': 7, 'I2~': 1, 'I2a': 5, 'I2a1': 4, 'I2a1a': 3, 'I2a1a2': 2, 'I2a1a2~': 1, 'IJ': 3, 'IJK': 2, 'L1a2': 1}
However, as explained above, there is one issue. For example, F should be equal at one and not 2. The reason is because with the code above, I look for F anywhere in the list. But I don't know how to correct that!
There is a second thing that I don't know how to do:
Based on the output:
{'A1': 3, 'A1b': 2, 'A1b1a1a2a1a~': 1, 'BT': 1, 'CF': 1, 'CT': 1, 'F': 2, 'GHIJK': 1, 'I': 12, 'I1a2a1a1d2a1a~': 1, 'I2': 7, 'I2~': 1, 'I2a': 5, 'I2a1': 4, 'I2a1a': 3, 'I2a1a2': 2, 'I2a1a2~': 1, 'IJ': 3, 'IJK': 2, 'L1a2': 1}
I would like to sum the values of the dic based on shared pattern:
example of the desired output{A1b1a1a2a1a~: 6, 'BT': 1,'CF': 1, 'CT': 1, 'F': 1, 'GHIJK': 1, 'I1a2a1a1d2a1a~': 13, I2a1a2:35, 'IJK': 5, 'IJK': 5}:
For example, A1b1a1a2a1a = 6 it's because it is made by A1 which has a value of 3, A1b with a value of 2 and the value of A1b1a1a2a1a equal at 1.
I don't know how to do that.
Any helps will be much appreciated!
Thanks
You count 'F' twice because you are iterating over the product of hg and hg so that the condition if ''.join(i) in ''.join(j) happens twice for 'F'. I solved that by checking the indexes.
You mentioned in the comment that the pattern should be at the beginning of the string so in doesn't work here. You can use .startswith() for that.
I first created a dictionary from the items but sorted(That's important for your second question about summing the values). They all start with the value of 1. Then I iterated over the the items, increased the value only if they are not in the same position.
For the second part of your question, because they are sorted, only the previous items can be at the beginning of the next items. So I got the pairs with .popitem() which hands the last pair (in Python 3.7 and above) and check its previous ones until the dictionary is empty.
hg = [['A1'], ['A1b'], ['A1b1a1a2a1a~'], ['BT'], ['CF'], ['CT'], ['F'], ['GHIJK'], ['I'], ['I1a2a1a1d2a1a~'], ['I2'], ['I2~'], ['I2a'], ['I2a1'], ['I2a1a'], ['I2a1a2'], ['I2a1a2~'], ['IJ'], ['IJK'], ['L1a2']]
# create a sorted dicitonary of all items each with the value of 1.
d = dict.fromkeys((item[0] for item in sorted(hg)), 1)
for idx1, (k, v) in enumerate(d.items()):
for idx2, item in enumerate(hg):
if idx1 != idx2 and item[0].startswith(k):
d[k] += 1
print(d)
print("-----------------------------------")
# last pair in `d`
k, v = d.popitem()
result = {k: v}
while d:
# pop last pair in `d`
k1, v1 = d.popitem()
# get last pair in `result`
k2, v2 = next(reversed(result.items()))
if k2.startswith(k1):
result[k2] += v1
else:
result[k1] = v1
print({k: result[k] for k in reversed(result)})
output:
{'A1': 3, 'A1b': 2, 'A1b1a1a2a1a~': 1, 'BT': 1, 'CF': 1, 'CT': 1, 'F': 1, 'GHIJK': 1, 'I': 11, 'I1a2a1a1d2a1a~': 1, 'I2': 7, 'I2a': 6, 'I2a1': 5, 'I2a1a': 4, 'I2a1a2': 3, 'I2a1a2~': 2, 'I2~': 2, 'IJ': 2, 'IJK': 1, 'L1a2': 1}
-----------------------------------
{'A1b1a1a2a1a~': 6, 'BT': 1, 'CF': 1, 'CT': 1, 'F': 1, 'GHIJK': 1, 'I1a2a1a1d2a1a~': 12, 'I2a1a2~': 27, 'I2~': 2, 'IJK': 3, 'L1a2': 1}
I think you made a mistake for your expected result and it should be like this, but let me know if mine is wrong.
#S.B helped me to better understand what I wanted to do, so I did some modifications to the second part of the script.
I converted the dictionary "d" (re-named "hg_d") into a list of list:
hg_d_to_list = list(map(list, hg_d.items()))
Then, I created a dictionary where the keys are the words and the values the list of the words that matches with startswith() like:
nested_HGs = defaultdict(list)
for i in range(len(hg_d_to_list)):
for j in range(i+1,len(hg_d_to_list)):
if hg_d_to_list[j][0].startswith(hg_d_to_list[i][0]):
nested_HGs[hg_d_to_list[j][0]].append(hg_d_to_list[i][0])
nested_HGs defaultdict(<class 'list'>, {'A1b': ['A1'], 'A1b1a1a2a1a': ['A1', 'A1b'], 'I1a2a1a1d2a1a~': ['I'], 'I2': ['I'], 'I2a': ['I', 'I2'], 'I2a1': ['I', 'I2', 'I2a'], 'I2a1a': ['I', 'I2', 'I2a', 'I2a1'], 'I2a1a2': ['I', 'I2', 'I2a', 'I2a1', 'I2a1a'], 'I2a1a2~': ['I', 'I2', 'I2a', 'I2a1', 'I2a1a', 'I2a1a2'], 'I2~': ['I', 'I2'], 'IJ': ['I'], 'IJK': ['I', 'IJ']})
Then, I sum each key and the value(s) associated to the dictionary "nested_HGs" based on the values of the dictionary "hg_d" like:
HGs_score = {}
for key,val in hg_d.items():
for key2,val2 in nested_HGs.items():
if key in val2 or key in key2:
if key2 not in HGs_score.keys():
HGs_score[key2]=val
else:
HGs_score[key2]+=val
HGs_score {'A1b': 5, 'A1b1a1a2a1a': 6, 'I1a2a1a1d2a1a~': 12, 'I2': 18, 'I2a': 24, 'I2a1': 29, 'I2a1a': 33, 'I2a1a2': 36, 'I2a1a2~': 38, 'I2~': 20, 'IJ': 13, 'IJK': 14}
Here, I realized that I don't care about the key with a value = at 1.
To finish, I get the key of the dictionary that has the highest value :
final_HG_classification = max(HGs_score, key=HGs_score.get)
final_HG_classification=I2a1a2~
It looks like it's working! Any suggestions or improvements are more than welcome.
Thanks in advance.

Filter dictionary and remove lowest values

I have dictionary as below. Is there a way to output a dictionary with the 5 highest values?
If there are ties for the 5th highest value, I need to include those keys.
Input dictionary:
{
"1": 1,
"12": 1,
"13":2,
"3": 5,
"5":8,
"7":3,
"4":8,
"10":7
}
Desired result:
{
"3": 5,
"5":8,
"7":3,
"4":8,
"10":7
}
Accounting for ties:
val = sorted(d.values(), reverse=True)[4]
res = {k: v for k, v in d.items() if v >= val}
print(res)
{'3': 5, '5': 8, '7': 3, '4': 8, '10': 7}
Explanation
Calculate the 5th highest value using sorted with reverse=True. Remember indexing begins at 0 so index with [4].
Use a dictionary comprehension to select all items from your dictionary where value is greater than the calculated value.
Optimisation
A more efficient method, as pointed out by #Chris_Rands, is to use heapq to calculate the 5th highest value:
import heapq
val = heapq.nlargest(5, d.values())[-1]
res = {k: v for k, v in d.items() if v >= val}
from collections import Counter
dict(Counter(your_dict).most_common(5))
OUTPUT:
{'10': 7, '3': 5, '4': 8, '5': 8, '7': 3}

How to convert string to integer without using library functions in Python?

I am trying to convert
a = "546"
to
a = 546
without using any library functions.
The "purest" I can think of:
>>> a = "546"
>>> result = 0
>>> for digit in a:
result *= 10
for d in '0123456789':
result += digit > d
>>> result
546
Or using #Ajax1234's dictionary idea if that's allowed:
>>> a = "546"
>>> value = {'0':0, '1':1, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9}
>>> result = 0
>>> for digit in a:
result = 10 * result + value[digit]
>>> result
546
You can keep a dictionary that stores the string and integer values of a numeric key, and then iterate over the string. While iterating over the string, you can use enumerate to keep track of the index and then raise 10 to that power minus 1 and then multiply by the corresponding key from the dictionary:
a = "546"
length = 0
for i in a:
length += 1
d = {'1': 1, '0': 0, '3': 3, '2': 2, '5': 5, '4': 4, '7': 7, '6': 6, '9': 9, '8': 8}
count = 0
counter = 0
for i in a:
count += (10**(length-counter-1)*d[i])
counter += 1
print(count)
Output:
546
The trick is that 546 = 500 + 40 + 6, or 5*10^2 + 4*10^1 + 6*10^0.
Note how the exponent is just the index (in reverse). Using that, you can generalize this approach into a function:
def strToInt(number):
total = 0 # this is where we accumulate the result
pwr = len(number) - 1 # start the exponent off as 2
for digit in number: # digit is the str "5", "4", and "6"
digitVal = ord(digit) - ord('0') # using the ascii table, digitVal is the int value of 5,4, and 6.
total += digitVal * (10 ** pwr) # add 500, then 40, then 6
pwr -= 1 # make sure to drop the exponent down by one each time
return total
And you can use it like so:
>>> strToInt("546")
546
def stringToInt(s):
result = 0
value = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
for digit in s:
result = 10 * result + value[digit]
return result
def int(a):
ty = a.__class__.__name__
out = 0
di = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4,
'5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
if ty not in ("str", "int", "float", "bytes"):
raise TypeError("unsupported format")
if a.__class__ == float:
return a.__floor__()
elif a.__class__ == int:
return a
else:
ind = 0
for val in a[::-1]:
if val not in di:
raise ValueError("invalid input")
out += di[val]*(10**ind)
ind += 1
#print(out, di[val])
return out
print(int("55"))
55
You can loop through the string and perform the operation on each character using ord.
example:
a="546"
num=0
for i in a:
num = num * 10 + ord(i) - ord('0')
astr = "1234"
num = 0
for index,val in enumerate(astr[::-1]):
res = (ord(val) - ord('0')) * (10 ** index)
num += (res)
a=input()
r=0
for i in a:
r=r*10+(ord(i)-ord("0"))
print(r)
print(type(r))

Calculating column wise for a matrix using numpy in python

By the following program, I am trying to calculate the number of occurance of '0','1','2',and '3' for each column. The program is not working as desired. I read somewhere that slicing of the matrix should be done for computing the occurance column wise but I am not sure how to do it. The program is written using numpy in python. How to do it using numpy?
import numpy as np
a=np.array([[ 2,1,1,2,1,1,2], #t1 is horizontal
[1,1,2,2,1,1,1],
[2,1,1,1,1,2,1],
[3,3,3,2,3,3,3],
[3,3,2,3,3,3,2],
[3,3,3,2,2,2,3],
[3,2,2,1,1,1,0]])
print(a)
i=0
j=0
two=0
zero=0
one=0
three=0
r=a.shape[0]
c=a.shape[1]
for i in range(1,r):
#print(repr(a))
for j in range(1,c):
#sele=a[i,j]
if (a[i,j]==0):
zero+=1
if (a[i,j]==1):
one+=1
if (a[i,j]==2):
two+=1
if (a[i,j]==3):
three+=1
if i==c-1:
#print(zero)
print(one)
i+=0
j=j+1
#print(two)
#print(three)
i=i+1
#print(zero)`
Also I want to print it in the following manner:
column: 0 1 2 3 4 5 6
occurrences: 0 0 0 0 0 0 0 1
1 1 3 2 2 4 3 1
2 2 1 3 4 1 2 2
3 4 3 2 1 2 2 2
Here is the code using list functionality
import numpy as np
inputArr=np.array([[ 2,1,1,2,1,1,2],
[1,1,2,2,1,1,1],
[2,1,1,1,1,2,1],
[3,3,3,2,3,3,3],
[3,3,2,3,3,3,2],
[3,3,3,2,2,2,3],
[3,2,2,1,1,1,0]
])
occurance = dict()
toFindList = [0,1,2,3]
for col in range(len(inputArr)):
collist = inputArr[:, col]
collist = (list(collist))
occurance['col_' + str(col)] = {}
for num in toFindList:
occurcount = collist.count(num)
occurance['col_' + str(col)][str(num)] = occurcount
for key, value in occurance.iteritems():
print key, value
Output:
col_2 {'1': 2, '0': 0, '3': 2, '2': 3}
col_3 {'1': 2, '0': 0, '3': 1, '2': 4}
col_0 {'1': 1, '0': 0, '3': 4, '2': 2}
col_1 {'1': 3, '0': 0, '3': 3, '2': 1}
col_6 {'1': 2, '0': 1, '3': 2, '2': 2}
col_4 {'1': 4, '0': 0, '3': 2, '2': 1}
col_5 {'1': 3, '0': 0, '3': 2, '2': 2}
This should give you the output format you want:
def col_unique(a):
return np.sum(np.dstack([np.in1d(a,i).reshape(a.shape) for i in np.unique(a)]), axis = 0).T

IterItems only looking at first value

I have a simple dictionary in python and I want to iterate over all of the items to print the key and value:
myDictionary = {"0" :0, "1":0, "2":0, "3":0, "4":0, "5":0, "6":12, "7":0,"8":0,"9":0,"10":0,"11":0, "12":0,"13":12}
def count(self, myDictionary):
for k, v in myDictionary.items():
print k,v
Python sees myDictionary as:
{'11': 0, '10': 0, '13': 12, '12': 0, '1': 0, '0': 0, '3': 0, '2': 0, '5': 0, '4': 0, '7': 0, '6': 12, '9': 0, '8': 0}
When the keys and values print out though, only 11 0 print. I also tried iteritems(). Why is only the first element in the dictionary being printed? I have python 2.3 if that makes a difference.
I made the assumption (based on the comments) that this snippet of code does not belong to a dictionary class but is rather a method, so I removed self (which is used to call other variables or methods within the class itself) and saw that the following code returned the result you wanted (running python 2.7.3):
>>>def count(myDictionary):
for k,v in myDictionary.items():
print k,v
>>>count(myDictionary)
11 0
10 0
13 12
12 0
1 0
0 0
3 0
2 0
5 0
4 0
7 0
6 12
9 0
8 0
>>>
This supports the need to update to 2.7x and to remove self when you call your method with just one dictionary (myDictionary) otherwise it will expect two arguments.
If you need the data to be stored in a class structure that can indeed be accomplished but I would only recommend that for a data structure more complicated than the one you posted such as a keyed dictionary where each key has multiple attributes that you would want to call separately. Such as:
dictionary = {v1: 0, 8, 9, v2: 9,6,3}
Where v1, and v2 represent 3D vectors with x, y, and z directions which you want to call individually without having to cycle through all of the data.

Categories

Resources