This question already has answers here:
Python - Caesar Cipher
(3 answers)
Closed 2 years ago.
This is a codecademy challenge, i am trying to offset the letters in the input string in relation to the english alphabet. lets say if we enter d with an offset of 3 it should return a. What am i doing wrong ?
I am new to python i started 3 days ago because of the quarantine, love it so far.
import string
a = list(string.ascii_lowercase)
word = "assa"
i = ""
j= ""
x = 0
for j in a:
for i in word:
if i == j:
x = (int(a.index(j)) - 10)
z = str(a[x])
sol = word.replace(i,z)
print(sol)
#def cipher(word):
sol = word.replace(i,z)
Every time, this goes back to the original value of word, figures out the result of making the replacement, and gives the name sol to the result. For your general approach to work, you would need to rename the result as word.
When you do this, you should not loop over the characters in word. .replace(i, z) already replaces every appearance of i with z (since i == j, you could equivalently have used j). It is also a bad idea to modify the thing you are looping over.
However, there is a much most straightforward way to implement this entire solution, using str.translate and str.maketrans - see for example.
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]
This question already has answers here:
Understanding slicing
(38 answers)
Closed 5 months ago.
s = "aB:cD"
def transform_string():
string_Length = len(s)
pos_colon = s.find(":")
lowerCase = s.lower()
upperCase = s.upper()
string_partA = 0 + pos_colon
res = lowerCase[:string_partA] + upperCase[string_partA:]
return res
print(transform_string())
print()
The code is meant to have the part of the string before the colon lowercased and after the colon uppercased. So my question is what is
res = lowerCase[:string_partA] + upperCase[string_partA:]
the bracket in there is meant to be for, or more explicitly, when can we use that? Does that syntax have a name? I saw someone else use it and I could logically follow how it works and what it does, I just wonder if that has a name or syntax restrictions and so on...
I first tried to use a for loop (would appreciate if someone could tell me why that is wrong, I know it's not as efficient as the code above):
s = "aB:cD"
def transform_string():
y = len(s)
x = s.find(":")
for s in range(0, x):
first_half = s.lower()
for s in range(x, y):
second_half = s.upper()
res = f"{first_half}+{second_half}"
return res
print(transform_string())
print()
Thanks!
The reason you are wrong is that you want to (lower) or (upper) (an integer).
When you put S in suffering, your S is equal to Integer
The first time (S=0), the second time (S=1) and so on until the end
But the above code finds out which section should be (lower) or (upper) by indexing
Meanwhile, when you want to get (Lens) because (S) is defined outside the function, (Len) cannot be calculated.
It is enough to write (global s) inside the function or give (s) as input to the function.
This question already has answers here:
confusion with encryption
(3 answers)
Closed 3 years ago.
I need to find the best way to assign each letter of the alphabet a random number 1-26 (using each number once). Or assign each number 1-26 a random letter of the alphabet (using each letter once).
For example:
a = 6, b = 12, c = 91
or
1 = g, 2 = a, 3 = k
I've tried assigning randint to each letter and repeating if the number has been used already but its really long.
Why not something like this?
import random
x=['A','B','C'.....]
y=list(range(1,27))
random.shuffle(y)
combo=list(zip(x,y))
you could of course make the final output a dict or something
This question already has answers here:
How to find elements that are common to all lists in a nested list?
(4 answers)
Closed 8 years ago.
t = input()
stringlist = []
setlist = []
for _ in range(t):
stringlist.append(raw_input())
print stringlist
for h in stringlist:
setlist.append((set(h)))
print setlist
print len((setlist[0] & setlist[1] & setlist[2]))
It's a simple program to find the number of common letters between the words that given as input. Note: This program only works for exactly 3 inputs. Can someone point me towards how I can generalize the last line of this code to allow for as many inputs as is supplied? I would appreciate it if you could just point me towards the answer and not actually give the answer.
So far Ive thought about using a join() to merge the input strings with the seperator being '&' and then put an eval() on the resulting string.
Just put all the input in a list then use map and set.intersection
l = ["foo", "boo", "foobar"]
common = set.intersection(*map(set,l))
print common
set(['o'])
Full code:
t = int(raw_input())
string_list = [raw_input() for _ in range(t)]
common = set.intersection(*map(set,string_list))
print(len(common))
Or cast the raw_input as a set if you don't need the list of words elsewhere:
string_list = [set(raw_input()) for _ in range(t)]
common = set.intersection(*string_list)
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