Python string manipulation using a dictionary - python

I'm working on a problem given to us by our professor and I can't get it to work how I want it to work. I should preface this by saying I'm a beginner with Python.
Essentially I'm to write a function that given a string returns the same string as a list with the objects of the list being different versions of the given string.
For example: Hello should return;
Hello
hEllo
heLlo
helLo
hellO
However we aren't allowed to use python's built in functions that can determine whether a character is upper or lower case such as upper() or lower() and having only really done any "programming" in MatLab prior to this and some OpenCV I'm looking for some help with getting started.
What I've tried so far is something like this:
def randRetur(menBok,dicT):
menBok = list(menBok)
for i,j in enumerate(menBok):
if menBok[i] in dicT.values():
scrambledPws.append(menBok)
else:
scrambledPws.append(dicT[j])
return scrambledPws
where my Dictionary maps lowercase letters to uppercase and scrambledPws is simply an empty list to start off with.
However this doesn't quite give me what I want but rather everything is capitalized in the first object of the list, which is where my understanding of how pythons handling of a for loop is very different to me from how for example MatLab handles it. I'm therefore more hoping for some guidance rather than how to do it, as I'm trying to learn.

The solution is very simple, I turned the string to a list and change the index of that list containing the character to its uppercase version. And then I turned the list back to a string and added it to combos. Then I returned the list of combos.
My explanation is not very good, sorry. But hopefully the code explains it better.
def scrambleString(string):
letters = { # Create a dictionary containing all the letters and their uppercase
"a": "A",
"b": "B",
"c": "C",
"d": "D",
"e": "E",
"f": "F",
"g": "G",
"h": "H",
"i": "I",
"j": "J",
"k": "K",
"l": "L",
"m": "M",
"n": "N",
"o": "O",
"p": "P",
"q": "Q",
"r": "R",
"s": "S",
"t": "T",
"u": "U",
"v": "V",
"w": "W",
"x": "X",
"y": "Y",
"z": "Z"
}
combos = []
for index, char in enumerate(string):
newString = list(string) # I turned the string into a list for easier manipulation
# The line below swaps the index of string to uppercase
newString[index] = letters[char]
returnString = "" # This is just to the list to a string
for i in newString:
returnString += i
combos.append(returnString) # Appends that scrambledString to a combo
return combos

see below
The idea is to use 2 dicts that will support lower to upper & upper to lower
l2u = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D', 'e': 'E', 'f': 'F', 'g': 'G', 'h': 'H', 'i': 'I', 'j': 'J', 'k': 'K', 'l': 'L', 'm': 'M', 'n': 'N', 'o': 'O', 'p': 'P', 'q': 'Q', 'r': 'R', 's': 'S', 't': 'T', 'u': 'U', 'v': 'V', 'w': 'W', 'x': 'X', 'y': 'Y', 'z': 'Z'}
u2l = {'A': 'a', 'B': 'b', 'C': 'c', 'D': 'd', 'E': 'e', 'F': 'f', 'G': 'g', 'H': 'h', 'I': 'i', 'J': 'j', 'K': 'k', 'L': 'l', 'M': 'm', 'N': 'n', 'O': 'o', 'P': 'p', 'Q': 'q', 'R': 'r', 'S': 's', 'T': 't', 'U': 'u', 'V': 'v', 'W': 'w', 'X': 'x', 'Y': 'y', 'Z': 'z'}
def get_str_versions(string):
result = []
for x in range(len(string)):
if string[x] in l2u:
result.append(string[0:x] + l2u[string[x]] + string[x+1:])
else:
result.append(string[0:x] + u2l[string[x]] + string[x+1:])
return result
print(get_str_versions('Hello'))
output
['hello', 'HEllo', 'HeLlo', 'HelLo', 'HellO']

This question has multiple parts, I can help with one part of it. For this part,
given some character, you need to return the uppercase variant, without using
the string method upper(). I am not sure the CPython implementation, but the
Ruby one is here:
https://github.com/ruby/ruby/blob/fb3c711d/regenc.c#L970-L977
Here is a simple implementation of that in Python:
def up(s_in):
n_out = ord(s_in) + ord('A') - ord('a')
return chr(n_out)
The input should be a single character, with output being the upper variant.
Note that this will only work on ASCII characters.

If you are not even allowed to use functions such as ord, which would allow you to check for case using the ascii table, you can manually map all printable characters (a-z) to an alternative-case version, save it into a dictionary, then add the reversed mapping (upper-case to lower-case) to the dictionary, then loop over all characters in a given word using index increment method (but even then, are you allowed to use len?).
For each iteration, you create a new string and then replace the current index in a string with a look-up alternative from the dictionary we created earlier.
CASE_MAPPING_ONE_SIDED = { "a": "A",
"b": "B",
"c": "C",
"d": "D",
"e": "E",
"f": "F",
"g": "G",
"h": "H",
"i": "I",
"j": "J",
"k": "K",
"l": "L",
"m": "M",
"n": "N",
"o": "O",
"p": "P",
"q": "Q",
"r": "R",
"s": "S",
"t": "T",
"u": "U",
"v": "V",
"w": "W", }
CASE_MAPPING = {}
# Map all lower-case characters to upper-case and also save it in the dictionary
for lower_ch in CASE_MAPPING_ONE_SIDED:
upper_ch = CASE_MAPPING_ONE_SIDED[lower_ch]
CASE_MAPPING[lower_ch] = upper_ch
CASE_MAPPING[upper_ch] = lower_ch
def alternative_versions(s):
res = [s]
i = 0
while i < len(s):
alt = s[:i]
# Replace the ith character with an alternative version
alt += CASE_MAPPING[s[i]]
alt += s[i+1:]
res.append(alt)
i += 1
return res
print(alternative_versions("Hello"))

here is some code (hope im not late because we had power go out):
from random import randint
uppercase = ['H', 'E', 'L', 'L', 'O']
lowercase = ['h', 'e', 'l', 'l', 'o']
random = randint(0, len(uppercase) - 1)
lowercase[random] = uppercase[random]
print(''.join(lowercase))

I assume the input string contains alphabets only.
def to_upper(ch):
return ch if (65 <= ord(ch) <= 90) else chr(ord(ch) - 32)
def capitalize(s):
diff = ord('a') - ord('A')
lower_case_word = ""
for ch in s:
if 65 <= ord(ch) <= 90: #Caps letter
lower_case_word = lower_case_word + chr(ord(ch)+diff)
else:
lower_case_word = lower_case_word + ch
for i in range(len(s)):
yield lower_case_word[:i] + to_upper(s[i]) + lower_case_word[i+1:]
for word in ("Hello", "myTest"):
print(list(capitalize(word)))
[Hello', 'hEllo', 'heLlo', 'helLo', 'hellO']
['Mytest', 'mYtest', 'myTest', 'mytEst', 'myteSt', 'mytesT']

Related

My code in Python is not replacing the string contents. Some of the letters seem to be missed

My code in Python is not replacing the string contents. Some of the letters seem to be missed. The output is
['x', 'y', 'p', 's', 'v', 'r', 'p', 'u', 'n', 'p']
['c', 'b', 'k', 'h', 'e', 'i', 'k', 'f', 'm', 'k']
but it seems .replace should be putting it back the way it was in the first place.
message = "cypherpunk"
new_message = []
for letter in message:
x = letter.replace("z","a").replace("y","b").replace("x","c").replace("w","d").replace("v","e").replace("u","f").replace("t","g").replace("s","h").replace("r","i").replace("q","j").replace("p","k").replace("o","l").replace("n","m").replace("m","n").replace("l","o").replace("k","p").replace("j","q").replace("i","r").replace("h","s").replace("g","t").replace("f","u").replace("e","v").replace("d","w").replace("c","x").replace("b","y").replace("a","z").replace("#","!")
new_message.append(x)
print(x)
print(new_message)
decode = []
for letter in new_message:
x = letter.replace("a","z").replace("b","y").replace("c","x").replace("d","w").replace("e","v").replace("f","u").replace("g","t").replace("h","s").replace("i","r").replace("j","q").replace("k","p").replace("l","o").replace("m","n").replace("n","m").replace("o","l").replace("p","k").replace("q","j").replace("r","i").replace("s","h").replace("t","g").replace("u","f").replace("v","e").replace("w","d").replace("x","c").replace("y","b").replace("z","a").replace("!","#")
decode.append(x)
print(decode)
The problem is that you're doing another replacement on the result of each preceding replacement. As a simple example, if you had:
message = "a"
x = message.replace("a", "z").replace("z", "a")
print(x)
this would print a because it first translates a to z, then it translates z to a. On the other hand,
message = "a"
x = message.replace("z", "a").replace("a", "z")
print(x)
will print z because the first replacement doesn't do anything (there's no z in z), so only the second replacement is effective.
Since you're doing the replacements in reverse alphabetic order during encoding, any letter that gets translated to an earlier letter in the alphabet gets translated back to itself. And during decoding, it's the opposite.
Instead of doing multiple calls to replace, use a dictionary with the translations:
encode_dict = {"a": "z", "b": "y", ..., "#": "!"}
decode_dict = {"a": "z", "b": "y", ..., "!": "#"}
message = "cypherpunk"
new_message = []
for letter in message:
x = encode_dict.get(letter, letter)
new_message.append(x)
print(new_message)
decode = []
for letter in new_message:
x = decode_dict.get(letter, letter)
decode.append(x)
print(decode)

scrabble word finder in Python

Implement the word_calculator method to return the correct scrabble word score. The scores are already set up to be use and are managed within dictionaries:
two = ['d', 'g']
three = ['b', 'c', 'm', 'p']
four = ['f', 'h', 'v', 'w', 'y']
five = ['k']
eight = ['j', 'x']
ten = ['q', 'z']
with having these list, i need to produce a function def word_calculator(word): where i need to pass a string to the method. the parameter zoo should return 12, and bus should return 5.
Can anyone help me to produce the function please?
This, like many problems in computer science, is much easier to do if you use a better data-structure.
As you have it, you will have to loop over all six lists for each letter, check if the letter is in each of them, and then hard code the score for each list programmatically so that you can add it to some total. That's a lot of work, and a lot of messy code.
However, you could use a dictionary instead. A dictionary lets you map any value to any other value. So, for example
x = {"A": 1, "B": 3}
Means that x["A"] is 1, and that x["B"] is 3, etc.
Lets imagine we had a dictionary containing the mapping of every letter to its scrabble value:
scores = {"A": 1, "B": 3, "C": 3, "D": 2, "E": 1, "F": 4, "G": 2, "H": 4, "I": 1, "J": 8, "K": 5, "L": 1, "M": 3, "N": 1, "O": 1, "P": 3, "Q": 1, "R": 1, "S": 1, "T": 1, "U": 1, "V": 4, "W": 4, "X": 8, "Y": 4, "Z": 10}
How would we find the word score for "ZOO"? We would need to:
Loop through every letter
Find the score for the letter (e.g. scores[letter])
Add the score to some running total
For example,
total = 0
for letter in "ZOO" :
total = total + score[letter]
print(total) # Prints 12
If you want to be fancy, this can also be done all on the one line using a list comprehension:
sum([scores[letter] for letter in "ZOO"])
Further reading:
https://docs.python.org/3/tutorial/datastructures.html
(explains dictionaries very well, and also talks about list comprehensions)
# the dictionary of scores to letter lists
score_letters = {
2: ['d', 'g'],
3: ['b', 'c', 'm', 'p'],
4: ['f', 'h', 'v', 'w', 'y'],
5: ['k'],
8: ['j', 'x'],
10: ['q', 'z']
}
# use `score_letters` to make a list from letters to score values
letter_scores = {letter: score for score, letters in score_letters.items() for letter in letters}
# equivalent to:
# letter_scores={}
# for score, letters in score_letters.items():
# for letter in letters:
# letter_scores[letter] = score
print('letter_scores =', letter_scores)
def word_calculator(word):
# sum the scores of each letter in the word
# `letter_scores.get(letter, 1)` means
# "get the value associated with the
# key `letter`, or if there is no such
# key in the dictionary, use the
# default value 1"
return sum(letter_scores.get(letter, 1) for letter in word)
print('zoo', word_calculator('zoo'))
print('bus', word_calculator('bus'))

Python Function that receives a letter and rotates that letter 13 places to the right

I'm trying to create a Python function that uses the Caesar cipher to encrypt a message.
So far, the code I have is
letter = input("Enter a letter: ")
def alphabet_position(letter):
alphabet_pos = {'A':0, 'a':0, 'B':1, 'b':1, 'C':2, 'c':2, 'D':3,
'd':3, 'E':4, 'e':4, 'F':5, 'f':5, 'G':6, 'g':6,
'H':7, 'h':7, 'I':8, 'i':8, 'J':9, 'j':9, 'K':10,
'k':10, 'L':11, 'l':11, 'M':12, 'm':12, 'N': 13,
'n':13, 'O':14, 'o':14, 'P':15, 'p':15, 'Q':16,
'q':16, 'R':17, 'r':17, 'S':18, 's':18, 'T':19,
't':19, 'U':20, 'u':20, 'V':21, 'v':21, 'W':22,
'w':22, 'X':23, 'x':23, 'Y':24, 'y':24, 'Z':25, 'z':25 }
pos = alphabet_pos[letter]
return pos
When I try to run my code, it will ask for the letter but it doesn't return anything after that
Please help if you have any suggestions.
you would need to access your dictionary in a different way:
pos = alphabet_pos.get(letter)
return pos
and then you can finally call the function.
alphabet_position(letter)
You can define two dictionaries, one the reverse of the other. You need to be careful on a few aspects:
Whether case is important. If it's not, use str.casefold as below.
What happens when you roll off the end of the alphabet, e.g. 13th letter after "z". Below we assume you start from the beginning again.
Don't type out the alphabet manually. You can use the string module.
Here's a demo:
letter = input("Enter a letter: ")
from string import ascii_lowercase
def get_next(letter, n):
pos_alpha = dict(enumerate(ascii_lowercase))
alpha_pos = {v: k for k, v in pos_alpha.items()}
return pos_alpha[alpha_pos[letter.casefold()] + n % 26]
get_next(letter, 13)
Enter a letter: a
'n'
If you need a entirely new encoded dict
import string
import numpy as np, random
letters = string.ascii_uppercase
d=dict(zip(list(letters),range(0,len(letters))))
encoded_dic={}
def get_caesar_value(v, by=13):
return(v+by)%26
for k,v in d.items():
encoded_dic[k]=chr(65+get_caesar_value(v))
print(encoded_dic)
Output:
{'A': 'N', 'C': 'P', 'B': 'O', 'E': 'R', 'D': 'Q', 'G': 'T', 'F': 'S', 'I': 'V', 'H': 'U', 'K': 'X', 'J': 'W', 'M': 'Z', 'L': 'Y', 'O': 'B', 'N': 'A', 'Q': 'D', 'P': 'C', 'S': 'F', 'R': 'E', 'U': 'H', 'T': 'G', 'W': 'J', 'V': 'I', 'Y': 'L', 'X': 'K', 'Z': 'M'}
The code you have only maps letters to a position. We'll rewrite it and make a rotate function.
Code
import string
import itertools as it
LOOKUP = {
**{x:i for i, x in enumerate(string.ascii_lowercase)},
**{x:i for i, x in enumerate(string.ascii_uppercase)}
}
def abc_position(letter):
"""Return the alpha position of a letter."""
return LOOKUP[letter]
def rotate(letter, shift=13):
"""Return a letter shifted some positions to the right; recycle at the end."""
iterable = it.cycle(string.ascii_lowercase)
start = it.dropwhile(lambda x: x != letter.casefold(), iterable)
# Advance the iterator
for i, x in zip(range(shift+1), start):
res = x
if letter.isupper():
return res.upper()
return res
Tests
func = abc_position
assert func("a") == 0
assert func("A") == 0
assert func("c") == 2
assert func("z") == 25
func = rotate
assert func("h") == "u"
assert func("a", 0) == "a"
assert func("A", 0) == "A"
assert func("a", 2) == "c"
assert func("c", 3) == "f"
assert func("A", 2) == "C"
assert func("a", 26) == "a"
# Restart after "z"
assert func("z", 1) == "a"
assert func("Z", 1) == "A"
Demo
>>> letter = input("Enter a letter: ")
Enter a letter: h
>>> rot = rotate(letter, 13)
>>> rot
'u'
>>> abc_position(rot)
20
Here we rotated the letter "h" 13 positions, got a letter and then determined the position of this resultant letter in the normal string of abc's.
Details
abc_position()
This function was rewritten to lookup the position of a letter. It merges two dictionaries:
one that enumerates a lowercase ascii letters
one that enumerates a uppercase ascii letters
The string module has this letters already.
rotate()
This function only rotates lowercase letters; uppercase letters are translated from the lowercase position. The string of letters is rotated by making an infinite cycle (an iterator) of lowercase letters.
The cycle is first advanced to start at the desired letter. This is done by dropping all letters that don't look like the one passed in.
Then it is advanced in a loop some number of times equal to shift. The loop is just one way to consume or move the iterator ahead. We only care about the last letter, not the ones in between. This letter is returned, either lower or uppercase.
Since a letter is returned (not a position), you can now use your abc_position() function to find it's normal position.
Alternatives
Other rotation functions can substitute rotate():
import codecs
def rot13(letter):
return codecs.encode(letter, "rot13")
def rot13(letter):
table = str.maketrans(
"ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz",
"NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm")
return str.translate(letter, table)
However, these options are constrained to rot13, while rotate() can be shifted by any number. Note: rot26 will cycle back to the beginning, e.g. rotate("a", 26) -> a.
See also this post on how to make true rot13 cipher.
See also docs on itertools.cycle and itertools.dropwhile.
You can do it with quick calculations from ord and chr functions instead:
def encrypt(letter):
return chr((ord(letter.lower()) - ord('a') + 13) % 26 + ord('a'))
so that:
print(encrypt('a'))
print(encrypt('o'))
outputs:
n
b

why does dictionnary only print the last 3 items? [duplicate]

This question already has answers here:
How can one make a dictionary with duplicate keys in Python?
(9 answers)
Closed 6 years ago.
d ={"A":"h","K":"h","Q":"h","A":"c","K":"c","Q":"c","A":"d","K":"d","Q":"d","A":"s","K":"s","Q":"s"}
print(d)
When I do this, it prints out:
{'A': 's', 'Q': 's', 'K': 's'}
How do I get to print out everything? I have trouble finding out how to write a dictionary with the same values on different keys.
As others have mentioned in the comments, you cannot have duplicate key's in a dictionary, Python knows to update the existing key with the latest value it's been set to in the duplicate declarations.
You could have a Dictionary that has a tuple (immutable), or list (mutable) as its value.
So if you wanted to have the following coupled information:
'Ah', 'As', 'Ac', 'Ad' , 'Kh', 'Ks' ...
You could represent that data with:
d = { 'A' : ('h', 's', 'c', 'd'), 'K' : ('h', 's') }
A list value can also work if you wanted to mutate the data within the list. (or set if you do not want duplicate values)
d = { 'A' : ['h', 's', 'c', 'd'], 'K' : ['h', 's'] }
This way you have essentially factored out your common character to be your key.
You could have some other list data structure like this:
my_list = [["A", ["h", "c", "d", "s"]], ["K", ["h", "c", "d", "s"]], ["Q", ["h", "c", "d", "s"]]]
and maybe even convert it into a more usable dictionary, like this:
dic = {}
for item in my_list:
key = item[0]
value = item[1]
dic[key] = value
print(dic)
Output:
{'Q': ['h', 'c', 'd', 's'], 'K': ['h', 'c', 'd', 's'], 'A': ['h', 'c', 'd', 's']}

Indexing in Python

So, I have this bit of code here that I'm working on for a school
def sem1Sort(semester1, selectionSEM1):
for semester1["1"] in semester1:
if semester1["1"] in selectionSEM1:
print semester1["1"]
def main():
selectionSEM1 = ["a", "t", "b", "f", "d", "e"]
semester1 = {"1": ['a', 'e', 't', 'x', 'l', 'y'], "2": ['b', 'f', 'h', 'm', 'r', 'd'] ,
"3": ['a', 'b', 'j', 'k', 'o', 'q', 'u'], "4": ['c', 'l', 't', 'z', 'd', 'f'],
"5": [], "6": [], "7": [], "8": []}
main()
So in the sem1Sort(): method, it should grab the semester1 list, as well as the artificial selectionSEM1 list. After that for each different index in the list of semester["1"], if it is in selectionSEM1, it should print it, correct?
I think your question is "How do I get the classes that are found in both the student's selections and the classes available for a semester?". Without changing the way your data is formatted try this filtering method.
def sem1Sort(semester1, selectionSEM1):
for period in semester1:
if period == '1':
for cls in semester1[period]:
if cls in selectionSEM1:
print cls
alternately since you were only checking for the first period
def sem1Sort(semester1, selectionSEM1):
print '\n'.join([cls for cls in semester1['1'] if cls in selectionSEM1])

Categories

Resources