Matching keys and values of 2 dictionaries on the fly? - python-3.x

I'm looking for the process to happen on the fly since it can be generalized and also efficient.
This is the code I tried. It has the basic logic. However this does not work for all inputs.
result=[{4:5},{4:6},{4:7}]
new=[]
new=result.copy()
print("Original",result)
for i in range(0,len(result)-1):
for key, value in result[i].items():
for j in range(1,len(result)):
for key_1, value_1 in result[j].items() :
if i!=j:
if key==key_1:
print("when key=key\n",result[i],"=",result[j])
dict={value:value_1}
new[j]=dict
print(new)
break;
if key==value_1:
print("when key=value\n",result[i],"=",result[j])
dict={value:key_1}
new[j]=dict
print(new)
if value==value_1:
print("when value=value\n",result[i],"=",result[j])
dict={key:key_1}
new[j]=dict
print(new)
else:
break;
print("\nFinal =",new)
print("\nCorrect =[{4:5},{5:6},{6:7}]" )
input: [{4:5},{4:6},{4:7}]
output: [{4:5},{5:6},{6:7}]

Related

Generate interleavings of two strings in lexicographical order in Python

How to generate interleavings of two strings in lexicograhical order in python?
I was able to generate interleavings, but not in lexicographical order.
The input given was,
Input :
2
nkb gl
bn zh
Expected output:
Case #1:
glnkb
gnkbl
gnklb
gnlkb
ngkbl
ngklb
nglkb
nkbgl
nkgbl
nkglb
Case #2:
bnzh
bzhn
bznh
zbhn
zbnh
zhbn
This is my code --
def interleave(A,B,ans,m,n,idx):
if m == 0 and n == 0:
print("".join(ans))
return
if len(A)<=len(B):
if m!=0:
ans[idx]=A[0]
interleave(A[1:],B,ans,m-1,n,idx+1)
if n!=0:
ans[idx]=B[0]
interleave(A,B[1:],ans,m,n-1,idx+1)
else:
if n!=0:
ans[idx]=B[0]
interleave(A,B[1:],ans,m,n-1,idx+1)
if m!=0:
ans[idx]=A[0]
interleave(A[1:],B,ans,m-1,n,idx+1)
t=int(input())
count=0
for i in range(t):
count+=1
print("Case #%d:"%count)
A,B=input().split()
m,n=len(A),len(B)
ans=['']*(m+n)
idx=0
interleave(A,B,ans,m,n,idx)
Output of the code that I wrote was--
Case #1:
glnkb
gnlkb
gnkbl
gnklb
nkbgl
nkgbl
nkglb
nglkb
ngkbl
ngklb
Case #2:
bnzh
bznh
bzhn
zhbn
zbnh
zbhn
There is some problem in the logic. Please help me to figure it out.

Elifs conditions are not working in my program

This is my code that takes a number of codons. Codons are a group of three nucleotides, each coding for an Amino Acid
codon_sequence=[]
print("Enter no. of codons you want")
n=int(input())
for i in range(n):
codon=str(input())
codon_sequence.append(codon)
print(codon_sequence)
for i in range(n):
if(codon_sequence[i]=="UUU" or "UUC" or "TTT" or "TTC"):
print("Phe_")
elif(codon_sequence[i]=="UUA" or "UUG" or "CUU" or "CUC" or "CUG" or "CUA" or "TTA" or "TTG" or "CTT" or "CTC" or "CTG" or "CTA"):
print("Leu_")
elif(codon_sequence[i]=="UCU" or "UCC" or "UCG" or "UCA" or "AGU" or "AGC" or "TCT" or "TCC" or "TCG" or "TCA" or "AGT" or "AGC"):
print("Ser_")
elif(codon_sequence[i]=="UAU" or "UAC" or "TAT" or "TAC"):
print("Tyr_")
elif(codon_sequence[i]=="UGU" or "UGC" or "TGT" or "TGC"):
print("Cys_")
elif(codon_sequence[i]=="UGG" or "TGG"):
print("Trp_")
elif(codon_sequence[i]=="CCU" or "CCC" or "CCA" or "CCG" or "CCT"):
print("Pro_")
elif(codon_sequence[i]=="CGU" or "CGC" or "CGA" or "CGG" or "AGA" or "AGG" or "CGT"):
print("Arg_")
elif(codon_sequence[i]=="CAU" or "CAC" or "CAT"):
print("His_")
elif(codon_sequence[i]=="CAA" or "CAG"):
print("Gln_")
elif(codon_sequence[i]=="AUU" or "AUC" or "AUA" or "ATT" or "ATC" or "ATA"):
print("Ile_")
elif(codon_sequence[i]=="AUG"):
print("Met_")
elif(codon_sequence[i]=="ACU" or "ACC" or "ACA" or "ACG" or "ACT"):
print("Thr_")
elif(codon_sequence[i]=="GUU" or "GUC" or "GUA" or "GUG" or "GTT" or "GTC" or "GTA" or "GTG"):
print("Val_")
elif(codon_sequence[i]=="GCU" or "GCC" or "GCA" or "GCG" or "GCT"):
print("Ala_")
elif(codon_sequence[i]=="GGU" or "GGC" or "GGA" or "GGG" or "GGT"):
print("Gly_")
elif(codon_sequence[i]=="GAU" or "GAC" or "GAT"):
print("Asp_")
elif(codon_sequence[i]=="GAA" or "GAG"):
print("Glu_")
elif(codon_sequence[i]=="AAU" or "AAC" or "AAT"):
print("Asn_")
elif(codon_sequence[i]=="AAA" or "AAG"):
print("Lys_")
else:
print("Stop_")
This is however, giving me only 'Phe_' as result, and ignores all other conditions
Reason why your code is not hitting the elif blocks
Your if and elif blocks should look like this.
It should check if codon_sequence[i] is equal to a string of interest.
if(codon_sequence[i]=="UUU" or codon_sequence[i]=="UUC" or codon_sequence[i]=="TTT" or codon_sequence[i]=="TTC"):
Instead you have an or condition against just plain strings like UUC.
This will result in the first if condition always being True.
Thereby you will never hit the elif block.
Also a better way of writing the if statement would be:
if codon_sequence[i] in ["UUU", "UUC", "TTT", "TTC"]:
print("Phe_")
This would be a great candidate for a switch statement, but as the previous answer mentioned you can't put an "or" between each string like you're doing.

How to apply recursion over this problem and solve this problem

The Problem is:-
Given a digit string, return all possible letter combinations of each digits according to the buttons on a telephone, that the number could represent.
The returned strings must be lexicographically sorted.
Example-1 :-
Input : “23”
Output : ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]
Example-2 :-
Input : “9”
Output: [“w”, “x”, “y”, “z”]
Example-3 :-
Input : “246”
Output : ["agm", "agn", "ago", "ahm", ..., "cho", "cim", "cin" "cio"] {27 elements}
I've squeezed my brain on this, and I've tried a lot but I'm not getting ahead of this part, what I've tried is to use a recursive function that zips the individual letters of each digit with each other letters and use itertools.combinations() over it, but I'm unable to complete this function and I'm unable to get ahead of this.
What I've tried is :-
times, str_res = 0, ""
def getval(lst, times):
if times==len(lst)-1:
for i in lst[times]:
yield i
else:
for i in lst[times]:
yield i + getval(lst, times+1)
dct = {"2":("a","b","c"), "3":("d","e","f"), "4":("g","h","i"),
"5":("j","k","l"), "6":("m","n","o"), "7":("p","q","r","s"),
"8":("t","u","v"), "9":("w","x","y","z"), "1":("")}
str1, res = "23", []
if len(str1)==1:
print(dct[str1[0]])
else:
temp = [dct[i] for i in str1]
str_res = getval(temp, times)
print(str_res)
Please suggest me your ideas over this problem or in completing the function...
It's not itertools.combinations that you need, it's itertools.product.
from itertools import product
def all_letter_comb(s, dct):
for p in product(*map(dct.get, s)):
yield ''.join(p)
dct = {"2":("a","b","c"), "3":("d","e","f"), "4":("g","h","i"),
"5":("j","k","l"), "6":("m","n","o"), "7":("p","q","r","s"),
"8":("t","u","v"), "9":("w","x","y","z"), "1":("")}
for s in ['23', '9', '246']:
print(s)
print(list(all_letter_comb(s, dct)))
print()
Output:
23
['ad', 'ae', 'af', 'bd', 'be', 'bf', 'cd', 'ce', 'cf']
9
['w', 'x', 'y', 'z']
246
['agm', 'agn', 'ago', 'ahm', 'ahn', 'aho', 'aim', 'ain', 'aio', 'bgm', 'bgn', 'bgo', 'bhm', 'bhn', 'bho', 'bim', 'bin', 'bio', 'cgm', 'cgn', 'cgo', 'chm', 'chn', 'cho', 'cim', 'cin', 'cio']
If I am not wrong this is leet code problem. You can find multiple answers there.

Python 3: How Do I Invert A Dictionary That Has A List As A Value

So for class I need to take a dictionary that has a list as a value and invert it. I have found several ways to do this, but the issue is when there are non-unique values. I found a way to do this but I feel like there must be much easier and streamlined ways to do this.
summon_locations = {
"Solaire": ['Gargoyles' ,'Gaping Dragon', "Ornstein/Smough"],
"Gotthard": ['Abyss Watchers' ,'Pontiff Sulyvahn', "Grand Archives"],
"Lucatiel": ['Lost Sinner', 'Smelter Demon', 'The Rotten'],
}
#Original dictionary
summon_locations = {
"Solaire": ['Gargoyles' ,'Gaping Dragon', "Ornstein/Smough"],
"Gotthard": ['Abyss Watchers' ,'Pontiff Sulyvahn', "Grand Archives"],
"Lucatiel": ['Lost Sinner', 'Smelter Demon', 'Abyss Watchers'],
}
#Dictionary with a non-unique value
def invert(d):
big_dict = {}
for k, v in d.items():
for i in v:
if i not in big_dict:
big_dict[i] = [k]
else:
big_dict[i].append(k)
return big_dict
print(invert(summon_locations))
Output Original:
{'Gargoyles': ['Solaire'], 'Gaping Dragon': ['Solaire'], 'Ornstein/Smough': ['Solaire'], 'Abyss Watchers': ['Gotthard'], 'Pontiff Sulyvahn': ['Gotthard'], 'Grand Archives': ['Gotthard'], 'Lost Sinner': ['Lucatiel'], 'Smelter Demon': ['Lucatiel'], 'The Rotten': ['Lucatiel']}
Output One non-unique value:
{'Gargoyles': ['Solaire'], 'Gaping Dragon': ['Solaire'], 'Ornstein/Smough': ['Solaire'], 'Abyss Watchers': ['Gotthard', 'Lucatiel'], 'Pontiff Sulyvahn': ['Gotthard'], 'Grand Archives': ['Gotthard'], 'Lost Sinner': ['Lucatiel'], 'Smelter Demon': ['Lucatiel']}
So it will just take the original key of a duplicate value and append it to a list. I have seen some cool ways to go about inverting dictionaries but they tend to fail here due to the lists.
You can use a defaultdict to remove the else statement and to check if the key exists. If it doesn't exists an empty list will be created.
from pprint import pprint
summon_locations = {
"Solaire": ['Gargoyles', 'Gaping Dragon', "Ornstein/Smough"],
"Gotthard": ['Abyss Watchers', 'Pontiff Sulyvahn', "Grand Archives"],
"Lucatiel": ['Lost Sinner', 'Smelter Demon', 'Abyss Watchers'],
}
if __name__ == '__main__':
from collections import defaultdict
inverted = defaultdict(list)
for key, values in summon_locations.items():
for value in values:
inverted[value].append(key)
pprint(inverted)
Output
defaultdict(<class 'list'>,
{'Abyss Watchers': ['Gotthard', 'Lucatiel'],
'Gaping Dragon': ['Solaire'],
'Gargoyles': ['Solaire'],
'Grand Archives': ['Gotthard'],
'Lost Sinner': ['Lucatiel'],
'Ornstein/Smough': ['Solaire'],
'Pontiff Sulyvahn': ['Gotthard'],
'Smelter Demon': ['Lucatiel']})
Which is similar to the the one-liner
[inverted[value].append(key) for key, values in summon_locations.items() for value in values]
But one liners are not always better, in this case I would stay with the two for loops.
You can replace your if else :
def invert(d):
big_dict = {}
for k, v in d.items():
for i in v:
big_dict[i] = big_dict.get(i, []) + [k]
return big_dict
However I can't find a way to skip one for.

Renaming dictionary keys through a loop problem

I have a column, 'EDU', in my dataframe, df. where I tried to create a dictionary with value_counts(), poe_dict. It looks like this.
edu_m=df['EDU'].sort_values()
poe_dict = edu_m.value_counts(normalize=True).to_dict()
poe_dict
{4: 0.47974705779026877,
3: 0.24588090637625154,
2: 0.172352011241876,
1: 0.10202002459160373}
Now, I'm trying to replace the keys '4,3,2,1' with these strings which I put in a list.
n_keys=["college","more than high school but not college","high school","less than high school"]
If I do each of them individually, this runs ok, giving me the expected result.
In:
poe_dict['college'] = poe_dict.pop(4)
poe_dict['more than high school but not college'] = poe_dict.pop(3)
poe_dict['high school'] = poe_dict.pop(2)
poe_dict['less than high school'] = poe_dict.pop(1)
Out:
{'college': 0.47974705779026877,
'more than high school but not college': 0.24588090637625154,
'high school': 0.172352011241876,
'less than high school': 0.10202002459160373}
however, if I try to do it as a loop, it produces this.
In:
for key, n_key in zip(poe_dict.keys(), n_keys):
poe_dict[n_key] = poe_dict.pop(key)
poe_dict
Out:
{2: 0.172352011241876,
1: 0.10202002459160373,
'high school': 0.47974705779026877,
'less than high school': 0.24588090637625154}
So I dont understand why the loop does not work for keys 2 and 1?
I have tried to debug it as well to see what happens in the loop like this.
In:
for key, n_key in zip(poe_dict.keys(), n_keys):
print (key,n_key)
poe_dict[n_key] = poe_dict.pop(key)
Out:
4 college
3 more than high school but not college
college high school
more than high school but not college less than high school
You loop over the keys of poe_dict in the for loop. However the keys of poe_dict is modified when the statement is poe_dict[n_key] = poe_dict.pop(key) has been run. Therefore, the keys information gets wrong. The correct way is to store the keys of peo_dict into a list list(poe_dict.keys()) and loop over this new list of keys.
poe_dict = {4: 0.47, 3:0.25, 2:0.17, 1:0.10}
n_keys = ['college', 'more than high school but not college','high school', 'less than high school' ]
keylist = list(poe_dict.keys())
for key, n_key in zip(keylist, n_keys):
print (key,n_key)
poe_dict[n_key] = poe_dict.pop(key)
print (poe_dict)
The results will be
{'college': 0.47, 'more than high school but not college': 0.25, 'high school': 0.17, 'less than high school': 0.1}

Resources