Related
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'
implement in one line, using lambda expressions(map/filter/reduce),
function that gets list of different types and returns a dictionary which has these keys:
{‘c’: , ‘i’: , ‘f’: , ‘o’: }
'c' will present list of characters
'i' list of the integers
'f' list of the floats
'o' list of any other types
for exaple for the list:
myList = ['a', 2, 3, 's', 2.23]
the output will be:
{'c': ['a', 's'], 'i': [2, 3], 'f': [2.23], 'o': []}
So far is I made a method of it that works but I'll need somehow change it one line of code:
def q1a(myList):
myDict = dict.fromkeys(('c', 'i', 'f', 'o'))
myDict['c'] = list(filter(lambda x: type(x) is str, myList))
myDict['i'] = list(filter(lambda x: type(x) is int, myList))
myDict['f'] = list(filter(lambda x: type(x) is float, myList))
myDict['o'] = list(filter(lambda x: type(x) is not float and type(x) is not int and type(x) is not str, myList))
return myDict
You can use the below ugly one-liner
out = dict(zip(['c','i','f','o'], map(list, (filter(lambda x:isinstance(x,str), lst), filter(lambda x:isinstance(x,int), lst), filter(lambda x:isinstance(x,float), lst), filter(lambda x: not isinstance(x,(str,float,int)), lst)))))
You can also use functools.reduce with a helper function (not exactly one liner but doesn't need multiple filters so saves time):
def add(d, x):
d[x[0]].append(x[1])
return d
from functools import reduce
out = reduce(add,
map(lambda x: (('c',x) if isinstance(x,str)
else (('i',x) if isinstance(x,int)
else (('f',x) if isinstance(x,float)
else ('o',x)))), lst),
{'c':[],'i':[],'f':[],'o':[]})
Output:
{'c': ['a', 's'], 'i': [2, 3], 'f': [2.23], 'o': []}
This gets around the need to assign to the keys one at a time:
def q1a(myList):
return {
'c': list(filter(lambda x: type(x) is str, myList)),
'i': list(filter(lambda x: type(x) is int, myList)),
'f': list(filter(lambda x: type(x) is float, myList)),
'o': list(filter(lambda x: type(x) is not float and type(x) is not int and type(x) is not str, myList))
}
You could use list comprehensions and create a dictionary literal:
{
'c': [e for e in myList if type(e) is str],
'i': [e for e in myList if type(e) is int],
'f': [e for e in myList if type(e) is float],
'o': [e for e in myList if type(e) not in {float, int, str}]
}
The assignment seems to be asking you to take a functional approach to this and create a single operation.
One option would be a single reduce that manipulates a dict. This isn't as natural in python as in other languages because most dict operations return None. But you can still do it in a functional way if you try (it's a one-liner broken up for a (minor) improvement in readability):
from functools import reduce
l = ['a', 2, 3, 's', 2.23]
res = reduce(
lambda d, t: dict(d, **{t[1]: d[t[1]] + [t[0]]}),
map(lambda el: (el, {str: 'c', int: 'i', float: 'f'}.get(type(el), 'o')) , l),
dict.fromkeys('cifo', [])
)
print(res)
# {'c': ['a', 's'], 'i': [2, 3], 'f': [2.23], 'o': []}
This works by creating a list of tuples with the map():
list(map(lambda el: (el, {str: 'c', int: 'i', float: 'f'}.get(type(el), 'o')) , l),)
# [('a', 'c'), (2, 'i'), (3, 'i'), ('s', 'c'), (2.23, 'f')]
and then updating a dict inside the reduce that is initialized with empty lists created with dict.fromkeys('cifo', []).
If I'm writing this in Python, my first choice would be to skip the functional approach and use a boring for loop and a default dict.
from collections import defaultdict
def q1a(myList):
d = defaultdict(list)
for v in myList:
if isinstance(v, str):
type_code = 'c'
elif isinstance(v, int):
type_code = 'i'
elif isinstnace(v, float):
type_code = 'f'
else:
type_code = 'o'
d[tc].append(v)
return d
However, this suggests a solution using itertools.groupby. The big if statement makes for a simple function like
def type_code(v):
if isinstance(v, str):
type_code = 'c'
elif isinstance(v, int):
type_code = 'i'
elif isinstnace(v, float):
type_code = 'f'
else:
type_code = 'o'
return type_code
which could be written as a single conditional expression suitable for use in a lambda expression:
lambda v: ('c' if isinstance(v, str) else
'i' if isinstance(v, int) else
'f' if isinstance(v, float) else
'o')
In the following, I'll abbreviate the above lambda expression as tc for readability.
With itertools.groupby, you can partition a (sorted) list using a function that specifies which partition each element belongs to. The partitions so produced are suitable for use in a dict comprehension.
from itertools import groupby
def q1a(myList):
return {k: list(vs) for k, vs in groupby(sorted(myList, key=tc), tc)}
One slight glitch:
>>> q1a(['a', 2, 3, 's', 2.23])
{'c': ['a', 's'], 'f': [2.23], 'i': [2, 3]}
The result doesn't include a key that isn't produced by a value in the list. You'll have to merge the result with pre-initialized dict containing all the keys.
def q1a(myList):
return ({'c': [], 'i': [], 'f': [], 'o': []}
| {k: list(vs) for k, vs in groupby(sorted(myList, key=tc), tc)})
I don't use dict.fromKeys("cifo", []) because then each key defaults to a reference to the same empty list, rather than a distinct empty list for each.
You could use a double indirection to convert types into letters and setdefault to update the resulting dictionary:
def q1a(myList):
types = {str:'c', int:'i', float:'f'}
myDict = dict()
for x in myList:
myDict.setdefault(types.get(type(x),'o'),[]).append(x)
return myDict
myList = ['a', 2, 3, 's', 2.23]
print(q1a(myList))
{'c': ['a', 's'], 'i': [2, 3], 'f': [2.23]}
Using a defaultdict could simplify it a bit:
from collections import defaultdict
def q1a(myList):
types = defaultdict(lambda:'o',{str:'c', int:'i', float:'f'})
myDict = defaultdict(list)
for x in myList:
myDict[types[type(x)]].append(x)
return dict(myDict)
I am doing text recognition with pytesseract. Sometimes text is not properly extracted.
For example, "DDR4" might be interpreted as "ODR4"
Hence I have a dictionary which record all possible escape, and code to detect how many char needed to be replace and its index for example,
my_dictionary= {
'D': ['O', '0'],
'O': 'D',
'0': 'D'
}
user_input = "DDR4"
char_to_replace = 0
char_index = []
for index, val in enumerate(user_input):
if val in my_dictionary:
char_to_replace += 1
char_index.append(index)
In this case, how could I produce a list of all possible combination, for example
D0R4, DOR4, 00R4, 0OR4, OOR4, O0R4, 0DR4, ODR4
Appreciate for any inputs
This is what i have come up with, pretty ugly code and im sure it can be done much easier with itertools, but what the heck - i hope it helps:
my_dictionary = {
'D': ['O', '0'],
'O': 'D',
'0': 'D'
}
user_input = "DDR4"
def replace_char(variable=None, replace_index=None, replace_with=None):
"""Supplementary function"""
return variable[:replace_index] + replace_with + variable[replace_index+1:]
# create maximum required iterations (max len of list in dict)
number_of_iterations_required = max([len(f) for f in my_dictionary.values()])
# list for preliminary word combinations
baseword_combinations = [user_input]
for key, val in my_dictionary.items():
for idx, char in enumerate(user_input):
if char == key:
for v in val:
baseword_combinations.append(replace_char(variable=user_input, replace_index=idx, replace_with=v))
# list for final returns, again append initial input
possible_combinations = [user_input]
for word in baseword_combinations:
for idx, char in enumerate(word):
for key, val in my_dictionary.items():
for v in val:
if char == key:
possible_combinations.append(replace_char(variable=word, replace_index=idx, replace_with=v))
if char == val:
possible_combinations.append(replace_char(variable=word, replace_index=idx, replace_with=key))
# get rid of duplicates, print result
print(list(set(possible_combinations)))
Result:
['OOR4', '00R4', 'ODR4', 'D0R4', '0DR4', 'DDR4', '0OR4', 'O0R4', 'DOR4']
Edit
The part with the number_of_iterations_required was unused in my above code, also i reworked it a little to use list comprehension - which makes it much less understandable, but much shorter, so here you go:
my_dictionary = {
'D': ['O', '0'],
'O': 'D',
'0': 'D'
}
user_input = "DDR4"
def replace_char(variable=None, replace_index=None, replace_with=None):
"""Supplementary function"""
return variable[:replace_index] + replace_with + variable[replace_index+1:]
# list for preliminary word combinations
base = [user_input]
base.extend([replace_char(user_input, idx, v) for key, val in my_dictionary.items()
for idx, char in enumerate(user_input) for v in val if char == key])
# list for final results
final_results = [user_input]
final_results.extend([replace_char(word, idx, key) for word in base for idx, char in enumerate(word)
for key, val in my_dictionary.items() for v in val if char == val])
result = list(set(final_results))
print(result)
I'm try to solve this problem in this way,hope that can help you:
import itertools as it
my_list= ['D','O','0']
result = []
input = 'DDR4'
# 'DDR4' -> '**R4'
for i in range(len(my_list)):
if input[i] in my_list:
input = input.replace(input[i],'*')
for e in it.product('DO0',repeat=input.count('*')):
a = list(e)
input_copy = input
for i in a:
# print(i)
input_copy = input_copy.replace('*',i,1)
result.append(input_copy)
result:
['DDR4', 'DOR4', 'D0R4', 'ODR4', 'OOR4', 'O0R4', '0DR4', '0OR4', '00R4']
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 ]
So, I have read quite a few posts on flattening dictionaries recursively in Python. None (save one) have come close to what I'm looking for. First, a quick example of what I am trying to accomplish:
Example dictionary with mixed entries: (keys and values will always be of mixed types)
{'a': [{'b': {'c': 'd', 'e': 'f', 'g': 'h',
'i': {'j': {'k': ['l'], 'm': 'n'}},
'o': {'p': {'q': ['r', 's' ], 't': 'u'}}
}
}]
}
Desired output:
{'a/b/c/d',
'a/b/e/f',
'a/b/g/h',
'a/b/i/j/k/l',
'a/b/i/j/m/n',
'a/b/o/p/q/r',
'a/b/o/p/q/s',
'a/b/o/p/t/u'}
The function should (theoretically) work on lists as well.
To explain a bit about what I am doing, I am attempting to search through a Mac plist and other attempts to search by key or value have been shaky at best. To compensate, I want to try a different approach. Convert the dictionary to a list of 'paths' and then just search the paths.
I tried myself (and partially succeeded) and then I found a better solution in the form of this:
def flatten(structure, key="", path="", flattened=None):
if flattened is None:
flattened = {}
if type(structure) not in(dict, list):
flattened[((path + "/") if path else "") + key] = structure
elif isinstance(structure, list):
for i, item in enumerate(structure):
flatten(item, "", "/".join(filter(None,[path,key])), flattened)
else:
for new_key, value in structure.items():
flatten(value, new_key, "/".join(filter(None,[path,key])), flattened)
return flattened
This works well but there are a few undesired effects. First, the output is as follows:
{'a/b/c' : 'd',
'a/b/e' : 'f',
'a/b/g' : 'h',
'a/b/i/j/k/': 'l',
'a/b/i/j/m' : 'n',
'a/b/o/p/q/': 's',
'a/b/o/p/t' : 'u'}
This is returning a dictionary of key/value pairs. I'd rather have a list of string paths. Secondly, and more importantly, you'll notice, the script has stripped values where the value was a list. Only appending the last item of the list.
'a/b/o/p/q/': 's' # there should be another entry with 'r' as the value.
I have spent a fair amount of time fiddling with the output and trying to completely wrap my head around the problem to no avail. It may just be my lac of understanding Python, but the output I want should be possible.
I try not to ask questions unless I have run out of options and here I am. Please do not mark as a duplicate, as other questions aren't quite looking to accomplish what I am looking for.
Thank you for your time and assistance/guidance.
Python 2.7:
def flatten(structure):
if isinstance(structure, basestring):
return [structure]
ret = []
if isinstance(structure, list):
for v in structure:
ret.extend(flatten(v))
elif isinstance(structure, dict):
for k, v in structure.items():
ret.extend(k + '/' + f for f in flatten(v))
return ret
print sorted(flatten(structure))
Output:
['a/b/c/d', 'a/b/e/f', 'a/b/g/h', 'a/b/i/j/k/l', 'a/b/i/j/m/n', 'a/b/o/p/q/r', 'a/b/o/p/q/s', 'a/b/o/p/t/u']
Or, if you don't care about the order, you can simply print flatten(structure).
Here's how I would do it in Python 3.3+:
def flatten(exp):
def sub(exp, res):
if type(exp) == dict:
for k, v in exp.items():
yield from sub(v, res+[k])
elif type(exp) == list:
for v in exp:
yield from sub(v, res)
else:
yield "/".join(res+[exp])
yield from sub(exp, [])
testing:
l={'a': [{'b': {'c': 'd', 'e': 'f', 'g': 'h',
'i': {'j': {'k': ['l'], 'm': 'n'}},
'o': {'p': {'q': ['r', 's' ], 't': 'u'}}
}
}]
}
for i in sorted(flatten(l)):
print(i)
yields
a/b/c/d
a/b/e/f
a/b/g/h
a/b/i/j/k/l
a/b/i/j/m/n
a/b/o/p/q/r
a/b/o/p/q/s
a/b/o/p/t/u
EDIT translation to Python 2 is trivial:
def flatten(exp):
def sub(exp, res):
if type(exp) == dict:
for k, v in exp.items():
for r in sub(v, res+[k]):
yield r
elif type(exp) == list:
for v in exp:
for r in sub(v, res):
yield r
else:
yield "/".join(res+[exp])
for r in sub(exp, []):
yield r
then
>>> for i in sorted(flatten(l)):
... print i
...
a/b/c/d
a/b/e/f
a/b/g/h
a/b/i/j/k/l
a/b/i/j/m/n
a/b/o/p/q/r
a/b/o/p/q/s
a/b/o/p/t/u