I am trying to shift the letters of a string over by 1 each time a while loop runs(so "A" becomes "B", "B" becomes "C" and so on each time through).
I need to have each result displayed so I can compare them. What I don't want to do but know how to do is create 26 different functions each one shifting the letters one letter farther but this seems a bit ridiculous.
How do I assign a variable to ttk each time the while loop goes through?
I thought this would assign "ls" plus whatever the count was on (ls1, ls2, ls3...) to each variable but it does not. It throws an error every time.
def shift1(*args):
s = code.get()
storage = []
count = 1
while (count <= 26):
l = [ord(i) for i in s]
sh = ([chr(i + count) for i in l])
storage.append(sh)
("ls"+str(count)).set(storage(count - 1))
count += 1
It give me an error that says
AttributeError: 'str' object has no attribute 'set'
Like I said I could just use this function 26 times each time assigning a diff ttk variable.
def shift1(*args):
s = code.get()
l = [ord(i) for i in s]
sh1.set(''.join([chr(i + 1) for i in l]))
This will essentially bypass the loop, but I know there has to be a better way.
Very new to python and ttk so any help is appreciated.
You don't need to use a while loop, you can just iterate using a for loop instead. As with Bemmu's answer this forces the characters to be all upper case, as it makes it easier. But you can modified a little more so it checks based on upper or lower case characters.
def shift(str):
str =str.upper()
for i in range(26):
print "".join([chr((ord(x)-65+i)%26+65) for x in str])
shift("hello")
You can see this in operation here: http://codepad.org/OaBXM4s2
Here is a way to rotate the characters in a string around, assuming there are only A-Z letters in your string.
string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for i in range(10):
string = "".join([chr((ord(letter) - ord('A') + 1) % 26 + ord('A')) for letter in string])
print string
The idea is that each letter has an ASCII code difference from the letter A. So letter A would be 0, letter B is 1. When letter Z is shifted forward, it needs to go back to A. This is where the modulo (%) comes in, it shifts the letter Z back to A if needed.
Output:
BCDEFGHIJKLMNOPQRSTUVWXYZA
CDEFGHIJKLMNOPQRSTUVWXYZAB
DEFGHIJKLMNOPQRSTUVWXYZABC
EFGHIJKLMNOPQRSTUVWXYZABCD
FGHIJKLMNOPQRSTUVWXYZABCDE
GHIJKLMNOPQRSTUVWXYZABCDEF
HIJKLMNOPQRSTUVWXYZABCDEFG
IJKLMNOPQRSTUVWXYZABCDEFGH
JKLMNOPQRSTUVWXYZABCDEFGHI
KLMNOPQRSTUVWXYZABCDEFGHIJ
Related
I am trying to solve this problem on HackerRank and I am having a issue with my logic. I am confused and not able to think what I'm doing wrong, feels like I'm stuck in logic.
Question link: https://www.hackerrank.com/challenges/game-of-thrones/
I created a dictionary of alphabets with value 0. And then counting number of times the alphabet appears in the string. If there are more than 1 alphabet characters occurring 1 times in string, then obviously that string cannot become a palindrome. That's my logic, however it only pass 10/21 test cases.
Here's my code:
def gameOfThrones(s):
alpha_dict = {chr(x): 0 for x in range(97,123)}
counter = 0
for i in s:
if i in alpha_dict:
alpha_dict[i] += 1
for key in alpha_dict.values():
if key == 1:
counter += 1
if counter <= 1:
return 'YES'
else:
return 'NO'
Any idea where I'm going wrong?
Explanation
The issue is that the code doesn't really look for palindromes. Let's step through it with a sample text based on a valid one that they gave: aaabbbbb (the only difference between this and their example is that there is an extra b).
Your first for loop counts how many times the letters appear in the string. In this case, 3 a and 5 b with all the other characters showing up 0 times (quick aside, the end of the range function is exclusive so this would not count any z characters that might show up).
The next for loop counts how many character there are that show up only once in the string. This string is made up of multiple a and b characters, more than the check that you have for if key == 1 so it doesn't trigger it. Since the count is less than 1, it returns YES and exits. However aaabbbbb is not a palindrome unscrambled.
Suggestion
To fix it, I would suggest having more than just one function so you can break down exactly what you need. For example, you can have a function that would return a list of all the unscrambled possibilities.
def allUnscrambled(string)->list:
# find all possible iterations of the string
# if given 'aabb', return 'aabb', 'abab', 'abba', 'bbaa', 'baba', 'baab'
return lstOfStrings
After this, create a palindrome checker. You can use the one shown by Dmitriy or create your own.
def checkIfPalindrome(string)->bool:
# determine if the given string is a palindrome
return isOrNotPalindrome
Put the two together to get a function that will, given a list of strings, determine if at least one of them is a palindrome. If it is, that means the original string is an anagrammed palindrome.
def palindromeInList(lst)->bool:
# given the list of strings from allUnscrambled(str), is any of them a palindrome?
return isPalindromeInList
Your function gameOfThrones(s) can then call this palindromeInList( allUnscrambled(s) ) and then return YES or NO depending on the result. Breaking it up into smaller pieces and delegating tasks is usually a good way to handle these problems.
Corrected the logic in my solution. I was just comparing key == 1 and not with every odd element.
So the corrected code looks like:
for key in alpha_dict.values():
if key % 2 == 1:
counter += 1
It passes all the testcases on HackerRank website.
The property that you have to check on the input string is that the number of characters with odd repetitions must be less than 1. So, the main ingredients to cook you recipe are:
a counter for each character
an hash map to store the counters, having the characters as keys
iterate over the input string
A plain implementation could be:
def gameOfThrones(s):
counters = {}
for c in s:
counters[c] = counters.get(c, 0) + 1
n_odd_characters = sum(v % 2 for v in counters.values())
Using a functional approach, based on reduce from functools:
from functools import reduce
def gamesOfThrones(s):
return ['NO', 'YES'][len(reduce(
lambda x, y: (x | {y: 1}) if y not in x else (x.pop(y) and x),
s,
{}
)) <= 1]
If you want, you can use the Counter class from collections to make your code more concise:
def gamesOfThrones(s):
return ['NO', 'YES'][sum([v % 2 for v in Counter(s).values() ]) <= 1]
Probably an easy question, but I have searched it up everywhere and still cannot find the answer.
I was given the following global variables:
ADDITION = '+'
ARROWS = '><^V'
PERIOD = '.'
RANDOM_THINGS = '|*'
The idea is to make a function that takes in a string and an integer n and returns the string modified. When a repeated character in the string is found or when a specified number of characters has been travelled(integer n) (whichever comes first), the function should return a string that replaces ARROWS and RANDOM_THINGS with an 'X' up until the repetition. So for example;
>>>travelled('>.+^<>.X+V', 7)
'X.+XX>.X+V'
>>>travelled('.><V^+.><',2)
'XX<V^+.><'
So far I have the following code:
def travelled(s, n):
a = 0
for i in range(0, len(s)):
if a == 1:
break
for n in range (i+1, len(s)):
if s[i] == s[j]:
print(s[j:]) #characters that weren’t travelled
a = 1
break
But that only gives me the unchanged end of the string. I don’t know how to change the string characters based on the global variables. Please help. Thank you:)
I am starting to learn Python and looked at following website: https://www.w3resource.com/python-exercises/string/
I work on #4 which is "Write a Python program to get a string from a given string where all occurrences of its first char have been changed to '$', except the first char itself."
str="restart"
char=str[0]
print(char)
strcpy=str
i=1
for i in range(len(strcpy)):
print(strcpy[i], "\n")
if strcpy[i] is char:
strcpy=strcpy.replace(strcpy[i], '$')
print(strcpy)
I would expect "resta$t" but the actual result is: $esta$t
Thank you for your help!
There are two issues, first, you are not starting iteration where you think you are:
i = 1 # great, i is 1
for i in range(5):
print(i)
0
1
2
3
4
i has been overwritten by the value tracking the loop.
Second, the is does not mean value equivalence. That is reserved for the == operator. Simpler types such as int and str can make it seem like is works in this fashion, but other types do not behave this way:
a, b = 5, 5
a is b
True
a, b = "5", "5"
a is b
True
a==b
True
### This doesn't work
a, b = [], []
a is b
False
a == b
True
As #Kevin pointed out in the comments, 99% of the time, is is not the operator you want.
As far as your code goes, str.replace will replace all instances of the argument supplied with the second arg, unless you give it an optional number of instances to replace. To avoid replacing the first character, grab the first char separately, like val = somestring[0], then replace the rest using a slice, no need for iteration:
somestr = 'restart' # don't use str as a variable name
val = somestr[0] # val is 'r'
# somestr[1:] gives 'estart'
x = somestr[1:].replace(val, '$')
print(val+x)
# resta$t
If you still want to iterate, you can do that over the slice as well:
# collect your letters into a list
letters = []
char = somestr[0]
for letter in somestr[1:]: # No need to track an index here
if letter == char: # don't use is, use == for value comparison
letter = '$' # change letter to a different value if it is equal to char
letters.append(letter)
# Then use join to concatenate back to a string
print(char + ''.join(letters))
# resta$t
There are some need of modification on your code.
Modify your code with as given in below.
strcpy="restart"
i=1
for i in range(len(strcpy)):
strcpy=strcpy.replace(strcpy[0], '$')[:]
print(strcpy)
# $esta$t
Also, the best practice to write code in Python is to use Function. You can modify your code as given below or You can use this function.
def charreplace(s):
return s.replace(s[0],'$')[:]
charreplace("restart")
#'$esta$t'
Hope this helpful.
I'm absolutely terrible at Python and my Computer Programming class ends in two days (thank god), but I am having the hardest time figuring out what is probably the easiest code ever.
The instructions to my assignment state, "Write a program which reads in text until a '!' is found. Use an array of integers subscripted by the letters 'A' through 'Z'."
From what i have done so far:
msg = input("What is your message? ")
msg = msg.upper()
int_array = [0] * 26
for alph in range (65, 91):
char = chr(alph)
print(char)
(int_array[char])
any help would be greatly appreciated! thanks!
EDIT: This is the full assignment:
Write a program which reads in text from the keyboard until a ('!') is found.
Using an array of integers subscripted by the letters 'A' through 'Z', count the number occurrences of each letter (regardless of whether it is upper or lower case). In a separate counter, also count the total number of "other" characters ('.', '?', ' ', '2', etc.).
Print out the count for each letter found. Also, print the count of the non-letter characters.
By inspecting the array, print out the count of the number of vowels, and the number of consonants.
Print out which letter was found the most times. (Note there may be more than one letter which has the maximum count attached to it.) Print out which letter (or letters) was found the least number of times, but make certain to exclude letters which were not found at all.
UPDATE:
I have gotten this far with my code
msg = input("What is your message? ")
print ()
num_alpha = 26
int_array = [0] * num_alpha
for alpha in range(num_alpha):
int_array[alpha] = chr(alpha + 65)
print(int_array[alpha], end = "")
print()
lett = 0
otherch = 0
num_vowels = 0
num_consanants = 0
count_character = [0] * 100000
length = len(msg)
for character in msg.upper():
if character == "!":
print("lett =", lett)
print("other char = ", otherch)
print("num_vowels = ", num_vowels)
print("num_consanants = ", num_consanants)
elif character < "A" or letter > "Z":
otherch = otherch + 1
count_character[ord(character)] = count_character[ord(character)] + 1
else:
lett = lett + 1
count_character[ord(character)] = count_character[ord(character)] + 1
for character in msg:
print("character", character, "appeared" , count_character[ord(character)] , "times")
it's obviously not finished yet, but every time i print the last print statement, it says that each character appeared 0 times. can anybody help?
You're going to need to get clarification on this, because there's no such thing as "an array of integers subscripted by the letters 'A' through 'Z'" in Python.
Possible interpretations that I can think of:
It's supposed to be a dictionary rather than an array. Python dictionaries are similar to lists (the Python datatype that is roughly equivalent to "arrays" in other languages), but they can be subscripted by strings, whereas lists can be subscripted only by integers. This way, you can store an integer to be associated with each letter. This is how most Python programmers would generally do something like this.
You're supposed to use parallel lists. You can do this by making two lists of 26 elements each, one containing the letters 'A' through 'Z' and one containing integers. For each letter, you could then use the list.index method to find the index in the first list where that letter is, then look up that index in the second list. (In theory, you wouldn't really need the first list, since Python strings are like lists in that they can be subscripted with integers and support the index method. So you could use the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' instead of a list. Or you could use the ord function, which is the inverse of the chr function. But I don't know if you're supposed to use these features.)
I'm not 100% sure the following is right because I agree with the others that the assignment description is wonky. It looks like a C-based homework assignment lazily ported to Python. That said:
In principle rather than hardcoding the bounds of the alphabet I'd go with ord('A') and ord('Z')+1, so that I can say something like alphabet = list(range(ord('A'), ord('Z')+1))
Renaming int_array to counter might make it more obvious what you need to do in your inner loop (keeping in mind that you're using the letters as your indices. Or rather, you'd need something more like ord(letter)-ord('A') as your indices)
You don't want to loop over the alphabet; you want to loop over the input.
count should be initialized to [0]*27 to track "other" values. You can increment counter[-1] for non-alphabetic characters.
Your final value is chr of counter.index(max(counter)). You may find it more straightforward, or your teacher may find it more acceptable, to just write a for loop.
I'm trying to write a basic algorithm for encrypting a file. It takes the ASCII value of each character in a string and moves it up or down an amount depending on how long the password is, then you can layer more passwords on top.
def encrypt(s):
lenStr=s.__len__() #used later for working how far the int is moved
s=list(s) #converts the string to a list
for x in s:
s[x]=ord(s[x]) #the same index of the list is = to the value of the string
s[x]=chr(s[x])#is where it eventualy gets changed back to a str
s=ord(s) is the line which is throwing the error, i added int() around it but didnt help, same error
You're getting theTypeErrorexception because the value ofxin thes[x]=ord(s[x]) statement is one of the elements of the s list, so it's an individual character from the string argument passed toencrypt(). To fix that, just loop through all the possible indices of the s list which happens to be the same as the length as the original string:
def encrypt(s):
lenStr=len(s)
s=list(s) # convert the string to a list
for i in range(lenStr):
s[i]=ord(s[i])
s[i]=chr(s[i])
This will allow your code to run without getting that error. From your description of the encryption algorithm you're going to implement, one thing to watch out for is producing illegal 8-bit character values out of the range of 0-255. You can avoid that problem by simply applying the mod operator % to the intermediate results to keep the values in the proper range. Here's what I mean:
def encrypt(s):
lenStr = len(s)
s = list(s) # convert the string to a list
for i in range(lenStr):
s[i] = chr((ord(s[i]) + lenStr) % 256)
return ''.join(s) # convert list back into a string
Likewise, you'll have to do the same thing when you decrypt a string:
def decrypt(s):
lenStr = len(s)
s = list(s) # convert the string to a list
for i in range(lenStr):
s[i] = chr((ord(s[i]) - lenStr) % 256)
return ''.join(s) # convert list back into a string
enc = encrypt('Gnomorian')
print('encrypted:', enc)
dec = decrypt(enc)
print('decrypted:', dec)
Output:
encrypted: Pwxvx{rjw
decrypted: Gnomorian
Also note that not all the characters whose ord() values are in the range of 0-255 are printable, so you may want to restrict the encryption transformation even more if that's a requirement (that the encrypted version be printable).
x is a character from the string, not an integer. Let me illustrate:
>>> s = list('abcd')
>>> for x in s:
... print(x)
...
a
b
c
d
>>>
You want x to be integer values from 0 to the length of the string, like this:
>>> for x in range(len(s)):
... print(x)
...
0
1
2
3
>>>
So, your function should probably look like this (untested):
def encrypt(s):
lenStr=s.__len__() #used later for working how far the int is moved
s=list(s) #converts the string to a list
for x in range(len(s)):
s[x]=ord(s[x]) #the same index of the list is = to the value of the string
s[x]=chr(s[x])#is where it eventualy gets changed back to a str
I am guessing this is what you are aiming for:
def encrypt(s):
offset = len(s)
return ''.join(chr(ord(c) + offset) for c in s)
def decrypt(s):
offset = len(s)
return ''.join(chr(ord(c) - offset) for c in s)
Some tips:
Use len(s) instead of lenStr=s.__len__()
Naming values near their first use in the code improves readability.
Choose names that describe the use of the value.
Strings are iterable, same as lists. No need to convert a string into a list.
Learn and use list comprehensions and generators whenever possible, they are usually much faster, simpler, easier to read and less error prone to create.
Remember to accept and/or upvote answers that are helpful.