So i have to encode a message but it's a different encoding, if the input is CAT the output must be DQ6 it's supposed to encode changing every letter of the input into the upper left key on the keyboard, for example again: in: bear out: G3Q4. I tried to code this in dictionaries like this:
d1 = {"q": 1,"Q": 1,"w": 2,"W": 2,"e": 3,"E": 3,"r": 4,"R": 4,"t": 5,"T": 5,"y": 6,"Y": 6,"u": 7,"U": 7,"i": 8,"I": 8,"o": 9,"O": 9,"p": 0,"P": 0}
d2 = {"a": 'Q',"A": 'Q',"s": 'W',"S": 'W',"d": 'E',"D": 'E',"f": 'R',"F": 'R',"g": 'T',"G": 'T',"h": 'Y',"H": 'Y',"j": 'U',"J": 'U',"k": 'I',"K": 'I',"l": 'O',"L": 'O',"ñ": 'P',"Ñ": 'P'}
d3 = {"z": 'A',"Z": 'A',"x": 'S',"X": 'S',"c": 'D',"C": 'D',"v": 'F',"V": 'F',"b": 'G',"B": 'G',"n": 'H', "N": 'H',"m": 'J',"M": 'J',",": 'K',".": 'L',"-": 'Ñ'}
I tried this function to check for every key but everything i'm getting is "None" as the value.
text = input("Text: ")
def cif(text):
cifrd = ""
for i in text:
if i in d1:
cifrd += d1[(d1.index(i))%(len(d1))]
elif i in d2:
cifrd += d2[(d2.index(i))%(len(d2))]
elif i in d3:
cifrd += d3[(d3.index(i))%(len(d3))]
else:
cifrd += i
print("New text: ",cif(cifrd))
Appreciate any help.
Your encoding:
d1 = {"q": 1,"Q": 1,"w": 2,"W": 2,"e": 3,"E": 3,"r": 4,"R": 4,"t": 5,"T": 5,"y": 6,"Y": 6,"u": 7,"U": 7,"i": 8,"I": 8,"o": 9,"O": 9,"p": 0,"P": 0}
d2 = {"a": 'Q',"A": 'Q',"s": 'W',"S": 'W',"d": 'E',"D": 'E',"f": 'R',"F": 'R',"g": 'T',"G": 'T',"h": 'Y',"H": 'Y',"j": 'U',"J": 'U',"k": 'I',"K": 'I',"l": 'O',"L": 'O',"ñ": 'P',"Ñ": 'P'}
d3 = {"z": 'A',"Z": 'A',"x": 'S',"X": 'S',"c": 'D',"C": 'D',"v": 'F',"V": 'F',"b": 'G',"B": 'G',"n": 'H', "N": 'H',"m": 'J',"M": 'J',",": 'K',".": 'L',"-": 'Ñ'}
There are a few issues. See my comments
text = input("Text: ")
def cif(text):
cifrd = ""
for letter in text:
# There is no need to manually write out each dictionary and do a check
# Put the dictionaries in a list, iterate over each one, and if the letter
# is in the dictionary, you will get the respective letter back
for encode in [d1, d2, d3]:
# check if my letter is in the dictionary
actual = encode.get(letter)
# If you check a dictionary and the key is not there, you will get `None`, this if statement ensures you only append actual number/characters
if actual:
cifrd += str(actual)
# When using a function, return something if you need it outside of the function
return cifrd
decoded = cif(text)
print("New text: {}".format(decoded))
There are a number of issues with your code:
You need to return the "encoded" text at the end of the cif() function
You need to pass the text variable to the cif() function, not cifrd which isn't defined outside your function
Dictionaries do not have an .index() method, you access dictionary items by key, e.g., d1["q"] returns 1.
For what it's worth, there's no need to maintain three separate dictionaries, nor is there reason to maintain both lower- and upper-cased letters in your dictionary; store lower-cased or upper-cased keys, and transform the input to the correct case when accessing the translation, i.e., input "Q" -> lowercase "q" -> d1["q"].
Here:
mapping = {'q': 1, 'w': 2, 'e': 3, 'r': 4, 't': 5, 'y': 6, 'u': 7, 'i': 8, 'o': 9, 'p': 0,
'a': 'q', 's': 'w', 'd': 'e', 'f': 'r', 'g': 't', 'h': 'y', 'j': 'u', 'k': 'i', 'l': 'o', 'ñ': 'p',
'z': 'a', 'x': 's', 'c': 'd', 'v': 'f', 'b': 'g', 'n': 'h', 'm': 'j', ',': 'k', '.': 'l', '-': 'ñ'}
def cif(s: string) -> string:
encoded_string = ""
for char in s:
encoded_string += mapping.get(char.lower(), char) # leaves the character un-encoded, if the character does not have a mapping
return encoded string
I would actually suggest using str.translate(). You can pass two strings, the first being the input characters, the second being the characters to which those inputs should map:
t = str.maketrans("qwertyuiopasdfghjklñzxcvbnm,.-", "1234567890qwertyuiopasdfghjklñ")
"hello world".translate(t)
'y3oo9 294oe'
Related
I am trying to write a function which will count the number of characters present in an input string and store as key-value in a dictionary.The code is partially working i.e it is also counting the whitespaces present in between 2 words.How do I avoid counting the whitespaces?
#Store Characters of a string in a Dictionary
def char_dict(string):
char_dic = {}
for i in string:
if i in char_dic:
char_dic[i]+= 1
else:
char_dic[i]= 1
return char_dic
print(char_dict('My name is Rajib'))
You could just continue if the character is a white space:
def char_dict(string):
char_dic = {}
for i in string:
if ' ' == i:
continue
if i in char_dic:
char_dic[i] += 1
else:
char_dic[i]= 1
return char_dic
print(char_dict('My name is Rajib')) # {'j': 1, 'm': 1, 'M': 1, 'i': 2, 'b': 1, 'e': 1, 'a': 2, 'y': 1, 'R': 1, 'n': 1, 's': 1}
A cleaner solution would be:
from collections import defaultdict
def countNonSpaceChars(string):
charDic = defaultdict(lambda: 0)
for char in string:
if char.isspace():
continue
charDic[char] += 1
return dict(charDic)
print(countNonSpaceChars('My name is Rajib')) # {'i': 2, 'a': 2, 'R': 1, 'y': 1, 'M': 1, 'm': 1, 'e': 1, 'n': 1, 'j': 1, 's': 1, 'b': 1}
You can delete space -> string = string.replace (" ","")
def char_dict(string):
char_dic = {}
string=string.replace(" ","")
for i in string:
if i in char_dic:
char_dic[i]+= 1
else:
char_dic[i]= 1
return char_dic
print(char_dict('My name is Rajib'))
To simplify things for you, there's a library called collections that has a Counter function that will produce a dictionary of values and their occurrences in a string. Then, I would simply remove the whitespace key from the dictionary if it is present using the del keyword.
from collections import Counter
def char_dict(string):
text = 'My name is Rajib'
c = Counter(text)
if ' ' in c: del c[' ']
print(char_dict('My name is Rajib'))
This method is very readable and doesn't require too much reinventing.
This question already has answers here:
Counting each letter's frequency in a string
(2 answers)
Closed 4 years ago.
How do I create a function that will let me input a word, and it will execute to create a dictionary that counts individual letters in the code. I would want it to display as a dictionary, for example, by inputting 'hello' it will display {'e': 1, 'h': 1, 'l': 2, 'o': 1}
I AM ALSO required to have 2 arguments in the function, one for the string and one for the dictionary. THIS IS DIFFERENT to the "Counting each letter's frequency in a string" question.
For example, I think I would have to start as,
d = {}
def count(text, d ={}):
count = 0
for l in text:
if l in d:
count +=1
else:
d.append(l)
return count
But this is incorrect? Also Would i need to set a default value to text, by writing text ="" in case the user does not actually enter any word?
Furthermore, if there were existing values already in the dictionary, I want it to add to that existing list. How would this be achieved?
Also if there were already existing words in the dictionary, then how would you add onto that list, e.g. dct = {'e': 1, 'h': 1, 'l': 2, 'o': 1} and now i run in terminal >>> count_letters('hello', dct) the result would be {'e': 2, 'h': 2, 'l': 4, 'o': 2}
If you can use Pandas, you can use value_counts():
import pandas as pd
word = "hello"
letters = [letter for letter in word]
pd.Series(letters).value_counts().to_dict()
Output:
{'e': 1, 'h': 1, 'l': 2, 'o': 1}
Otherwise, use dict and list comprehensions:
letter_ct = {letter:0 for letter in word}
for letter in word:
letter_ct[letter] += 1
letter_ct
You can use pythons defaultdict
from collections import defaultdict
def word_counter(word):
word_dict = defaultdict(int)
for letter in word:
word_dict[letter] += 1
return(word_dict)
print(word_counter('hello'))
Output:
defaultdict(<class 'int'>, {'h': 1, 'e': 1, 'l': 2, 'o': 1})
def count_freqs(string, dictionary={}):
for letter in string:
if letter not in dictionary:
dictionary[letter] = 1
else:
dictionary[letter] += 1
return dictionary
If we had certain conditions to fulfill such as
a is the opposite of b
c is the opposite of h
l is the opposite of r
the opposite of the string acl would be bhr
Do you guys think you can help me figure out how I would go about building a function that when given two strings will return a boolean that lets me know whether the given strings are opposite. for example input: opposite("ahl","bcr") would return True while ("ahl","bbr") would return False.
I would do it like a string compare, except that for every character, there would be a lookup table to get a translated value like so:
lookup = {
'a': 'b',
'c': 'h',
'l': 'r'
}
def opposite(one, two):
count = 0
if len(one) != len(two):
return False
for i in one:
if (lookup[i] != two[count] ):
return False
count += 1
return True
if __name__ == '__main__':
print opposite('acl', 'bhr')
If you have the lookup table, then this is a one-liner.
lookup = {
'a': 'b',
'c': 'h',
'l': 'r'
}
def opposite(str1, str2):
return [ lookup[c] for c in str1] == [ c for c in str2 ]
Depending on the actual situation (whether you know the first string contains only "acl" and the second only their opposites), you may need to have bidirectional lookup:
lookup = {
'a': 'b',
'c': 'h',
'l': 'r',
'b': 'a',
'h': 'c',
'r': 'l'
}
And if you want to have an exception raised when there are invalid characters in the input, you may change the function:
def opposite(str1, str2):
return [ lookup[c] for c in str1] == [ lookup[lookup[c]] for c in str2 ]
I have a list of strings with prefix characters representing the multiplying factor for the number. So if I have data like:
data = ['101n', '100m', '100.100f']
I want to use the dictionary
prefix_dict = {'y': 'e-24', 'z': 'e-21', 'a': 'e-18', 'f': 'e-15', 'p': 'e-12',
'n': 'e-9', 'u': 'e-6', 'm': 'e-3', 'c': 'e-2', 'd': 'e-1',
'da': 'e1', 'h': 'e2', 'k': 'e3', 'M': 'e6', 'G': 'e9',
'T': 'e12', 'P': 'e15', 'E': 'e18', 'Z': 'e21', 'Y': 'e24'}
To insert their corresponding strings. When I look at the other questions similar to mine there is one character being translated into another character. Is there a way to use the translate function to translate one character into multiple characters or should I be approaching this differently?
You can use regex for this, this works for 'da' as well:
>>> data = ['101n', '100m', '100.100f', '1d', '1da']
>>> import re
>>> r = re.compile(r'([a-zA-Z]+)$')
>>> for d in data:
print r.sub(lambda m: prefix_dict.get(m.group(1), m.group(1)), d)
...
101e-9
100e-3
100.100e-15
1e-1
1e1
And a non-regex version using itertools.takewhile:
>>> from itertools import takewhile
>>> def find_suffix(s):
return ''.join(takewhile(str.isalpha, s[::-1]))[::-1]
...
>>> for d in data:
sfx = find_suffix(d)
print (d.replace(sfx, prefix_dict.get(sfx, sfx)))
...
101e-9
100e-3
100.100e-15
1e-1
1e1
Try:
for i, entry in enumerate(data):
for key, value in sorted(prefix_dict.items(),
key = lambda x: len(x[0]), reverse=True):
# need to sort the dictionary so that 'da' always comes before 'a'
if key in entry:
data[i] = entry.replace(key, value)
print(data)
This works for arbitrary combinations in the dictionary and the data. If the dictionary key is always only 1 string long, you have lots of other solutions posted here.
import re
data = ['101da', '100m', '100.100f']
prefix_dict = {'y': 'e-24', 'z': 'e-21', 'a': 'e-18', 'f': 'e-15', 'p': 'e-12',
'n': 'e-9', 'u': 'e-6', 'm': 'e-3', 'c': 'e-2', 'd': 'e-1',
'da': 'e1', 'h': 'e2', 'k': 'e3', 'M': 'e6', 'G': 'e9',
'T': 'e12', 'P': 'e15', 'E': 'e18', 'Z': 'e21', 'Y': 'e24'}
comp = re.compile(r"[^\[A-Za-z]")
for ind,d in enumerate(data):
pre = re.sub(comp,"",d)
data[ind] = d.replace(pre,prefix_dict.get(pre))
print data
['101e1', '100e-3', '100.100e-15']
You can use pre = [x for x in d if x.isalpha()][0] instead of using re
I want to make a function that goes through a list and makes a dictionary with keys for each thing in the list and values of the one thing in the list following the key.
def function(s : str) -> {str:{str}}:
listt=list(s)
dictt= {}
for i in listt[:-1]:
if i not in dictt:
dictt[i] = set()
dictt[i].update(listt[listt.index(i)+1])
return dictt
print(function('bookeeper'))
should return:
{'b': {'o'}, 'k': {'e'}, 'p': {'e'}, 'o': {'o', 'k'}, 'e': {'e', 'p', 'r'}}
but actually returns:
{'b': {'o'}, 'k': {'e'}, 'p': {'e'}, 'o': {'o'}, 'e': {'e'}}
Don't use list.index(); that'll only match the first occurrence of a letter; for 'o' it'll never find the second 'o'; you'll only repeatedly add the same characters to the sets.
Use enumerate() to add an index to your loop, instead:
def function(s : str) -> {str:{str}}:
listt=list(s)
dictt= {}
for next_index, char in enumerate(listt[:-1], 1):
if char not in dictt:
dictt[char] = set()
dictt[char].update(listt[next_index])
return dictt
I started enumerate() at 1 instead of the default 0 so it always represents the next position.
Demo:
>>> def function(s : str) -> {str:{str}}:
... listt=list(s)
... dictt= {}
... for next_index, char in enumerate(listt[:-1], 1):
... if char not in dictt:
... dictt[char] = set()
... dictt[char].update(listt[next_index])
... return dictt
...
>>> print(function('bookeeper'))
{'p': {'e'}, 'o': {'o', 'k'}, 'e': {'p', 'r', 'e'}, 'b': {'o'}, 'k': {'e'}}
Now that it is working, lets simplify this a little; use dict.setdefault() to add the set to the dictionary when the key is missing, for example. Strings are already sequences, no need to cast them to a list either:
def function(s : str) -> {str:{str}}:
dictt = {}
for next_index, char in enumerate(s[:-1], 1):
dictt.setdefault(char, set()).update(s[next_index])
return dictt
Instead of enumerate(), we could also use zip() to pair up the letters of the word:
def function(s : str) -> {str:{str}}:
dictt = {}
for char, next_char in zip(s, s[1:]):
dictt.setdefault(char, set()).update(next_char)
return dictt
Your problem is that index() always returns the first index in the string, so you'll be adding the same character to the set over and over.
Try something like
def function(s : str) -> {str:{str}}:
dictt = {}
for pos, char in enumerate(s[:-1]):
if char not in dictt:
dictt[char] = set()
dictt[char].update(s[pos+1])
return dictt
Here is the another answer:
def func(string):
arr = set(string)
res = {}
for char in arr:
index = [i for i in range(len(string)) if string[i] == char]
temp = []
for i in index:
if i == len(string) - 1:
continue
temp.append(string[i + 1])
if temp:
res[char] = temp
return res
func('bookeeper')
>>> {'b': ['o'], 'e': ['e', 'p', 'r'], 'k': ['e'], 'o': ['o', 'k'], 'p': ['e']}