compare the character in 2 strings taking into account the position - python

I am coding for a game similar to wordle
I need to compare 2 strings
If the character and position is the same to return -
If the character in guess is in the answer but wrong position to return *
If character completely not in answer to return .
If my answer has 2 similar characters (eg, guess: accept, answer: castle), * can only be returned once, meaning the expected output would be **.*.*
I can't seem to iterate the string taking into account the position as well
def process(guess: str, answer: str) -> str:
output = ""
for i,ch in enumerate(guess):
if ch not in answer:
output += '.'
elif ch != answer[i]:
output += '*'
else:
output += '-'
return output

You don't track the characters that you already identified in the answer, you can add a tracker string to check for identified characters:
def process(guess: str, answer: str) -> str:
output = ""
already_identified_characters = set()
for i, ch in enumerate(guess):
if ch not in answer or ch in already_identified_characters:
output += "."
elif ch != answer[i]:
output += "*"
else:
output += "-"
already_identified_characters.add(ch)
return output

If guess and answer are of equal length, this is how you could implement it:
def process(guess: str, answer: str) -> str:
output = []
misplaced_chars = set()
for g,a in zip(guess,answer):
if g == a:
# Identical character on same location
output.append('-')
elif g in answer and g not in misplaced_chars:
# Character exists in answer
output.append('*')
misplaced_chars.add(g)
else:
# Wrong guess
output.append('.')
return ''.join(output)

Using Counter to keep track of the letters used in the answer, you can make sure that if letters are repeated in answer, they will work properly as well.
Basically, you keep track of each letter's count in the input, and subtract from it as you encounter matches.
from collections import Counter
def process(guess: str, answer: str) -> str:
countAnswer = Counter(answer)
output = ""
for i,ch in enumerate(guess):
if ch not in answer:
output += '.'
elif countAnswer[ch]==0:
output += '.'
elif ch != answer[i] and countAnswer[ch]!=0:
output += '*'
countAnswer[ch]-=1
else:
output += '-'
return output
This should work out very similar to Wordle's treatment of repeated characters.
Various Inputs and their Outputs:
>>> process("crate","watch")
'*.**.'
>>> process("crate","slosh")
'.....'
>>> process("pious","slosh")
'..-.*'
>>> process("pesos","slosh")
'..***'

Related

Run Length Decoding

I have a function for run length decoding in Python. It is working with single digit numbers, but if my number is above 9, it doesn't work. As you can see in my code, I want to print c 11 times, but it only prints it one time. How can I fix it ? I want to keep the code I have, without any special libraries. Example: Input is (A2B3C11) then output should be (AABBBCCCCCCCCCCC), but currently my output is only (AABBBC)
def run_length_decoding(compressed_seq):
seq = ''
for i in range(0, len(compressed_seq)):
if compressed_seq[i].isalpha() == True:
for j in range(int(compressed_seq[i + 1])):
seq += compressed_seq[i]
return (seq)
print(run_length_decoding('A2B3C11'))
I'll preface this answer by saying a regex would solve this pretty nicely.
Trying to keep relatively closely to your original code without importing any additional modules:
def run_length_decoding(compressed_seq: str) -> str:
seq = ""
current_letter = None
for character in compressed_seq:
if character.isalpha():
if current_letter is not None:
seq += current_letter * int(number)
current_letter = character
number = ""
else:
# We assume that this is the number following the letter.
number += character
if current_letter is not None:
seq += current_letter * int(number)
return seq
Try it at https://www.mycompiler.io/view/CVsq0tCieVP

How to remove Triplicate Letters in Python

So I'm a little confused as far as putting this small code together. My teacher gave me this info:
Iterate over the string and remove any triplicated letters (e.g.
"byeee mmmy friiiennd" becomes "bye my friennd"). You may assume any
immediate following same letters are a triplicate.
I've mostly only seen examples for duplicates, so how do I remove triplicates? My code doesn't return anything when I run it.
def removeTriplicateLetters(i):
result = ''
for i in result:
if i not in result:
result.append(i)
return result
def main():
print(removeTriplicateLetters('byeee mmmy friiiennd'))
main()
I have generalized the scenario with "n". In your case, you can pass n=3 as below
def remove_n_plicates(input_string, n):
i=0
final_string = ''
if not input_string:
return final_string
while(True):
final_string += input_string[i]
if input_string[i:i+n] == input_string[i]*n:
i += n
else:
i += 1
if i >= len(input_string):
break
return final_string
input_string = "byeee mmmy friiiennd"
output_string = remove_n_plicates(input_string, 3)
print(output_string)
# bye my friennd
You can use this for any "n" value now (where n > 0 and n < length of input string)
Your code returns an empty string because that's exactly what you coded:
result = ''
for i in result:
...
return result
Since result is an empty string, you don't enter the loop at all.
If you did enter the loop you couldn't return anything:
for i in result:
if i not in result:
The if makes no sense: to get to that statement, i must be in result
Instead, do as #newbie showed you. Iterate through the string, looking at a 3-character slice. If the slice is equal to 3 copies of the first character, then you've identified a triplet.
if input_string[i:i+n] == input_string[i]*n:
Without going in to writing the code to resolve the problem.
When you iterate over the string, add that iteration to a new string.
If the next iteration is the same as the previous iteration then do not add that to the new string.
This will catch both the triple and the double characters in your problem.
Tweaked a previous answer to remove a few lines that were not needed.
def remove_n_plicates(input_string, n):
i=0
result = ''
while(True):
result += input_string[i]
if input_string[i:i+n] == input_string[i]*n:
i += n
else:
i += 1
if i >= len(input_string):
break
return result
input_string = "byeee mmmy friiiennd"
output_string = remove_n_plicates(input_string, 3)
print(output_string)
# bye my friennd
Here's a fun way using itertools.groupby:
def removeTriplicateLetters(s):
return ''.join(k*(l//3+l%3) for k,l in ((k,len(list(g))) for k, g in groupby(s)))
>>> removeTriplicateLetters('byeee mmmy friiiennd')
'bye my friennd'
just modifying #newbie solution and using stack data structure as solution
def remove_n_plicates(input_string, n):
if input_string =='' or n<1:
return None
w = ''
c = 0
if input_string!='':
tmp =[]
for i in range(len(input_string)):
if c==n:
w+=str(tmp[-1])
tmp=[]
c =0
if tmp==[]:
tmp.append(input_string[i])
c = 1
else:
if input_string[i]==tmp[-1]:
tmp.append(input_string[i])
c+=1
elif input_string[i]!=tmp[-1]:
w+=str(''.join(tmp))
tmp=[input_string[i]]
c = 1
w+=''.join(tmp)
return w
input_string = "byeee mmmy friiiennd nnnn"
output_string = remove_n_plicates(input_string, 3)
print(output_string)
output
bye my friennd nn
so this is a bit dirty but it's short and works
def removeTriplicateLetters(i):
result,string = i[:2],i[2:]
for k in string:
if result[-1]==k and result[-2]==k:
result=result[:-1]
else:
result+=k
return result
print(removeTriplicateLetters('byeee mmmy friiiennd'))
bye my friennd
You have already got a working solution. But here, I come with another way to achieve your goal.
def removeTriplicateLetters(sentence):
"""
:param sentence: The sentence to transform.
:param words: The words in the sentence.
:param new_words: The list of the final words of the new sentence.
"""
words = sentence.split(" ") # split the sentence into words
new_words = []
for word in words: # loop through words of the sentence
new_word = []
for char in word: # loop through characters in a word
position = word.index(char)
if word.count(char) >= 3:
new_word = [i for i in word if i != char]
new_word.insert(position, char)
new_words.append(''.join(new_word))
return ' '.join(new_words)
def main():
print(removeTriplicateLetters('byeee mmmy friiiennd'))
main()
Output: bye my friennd

Super Reduced String python

I've been having problems with this simple hackerrank question. My code works in the compiler but hackerrank test is failing 6 test cases. One of which my output is correct for (I didn't pay premium). Is there something wrong here?
Prompt:
Steve has a string of lowercase characters in range ascii[‘a’..’z’]. He wants to reduce the string to its shortest length by doing a series of operations in which he selects a pair of adjacent lowercase letters that match, and then he deletes them. For instance, the string aab could be shortened to b in one operation.
Steve’s task is to delete as many characters as possible using this method and print the resulting string. If the final string is empty, print Empty String
Ex.
aaabccddd → abccddd → abddd → abd
baab → bb → Empty String
Here is my code:
def super_reduced_string(s):
count_dict = {}
for i in s:
if (i in count_dict.keys()):
count_dict[i] += 1
else:
count_dict[i] = 1
new_string = ''
for char in count_dict.keys():
if (count_dict[char] % 2 == 1):
new_string += char
if (new_string is ''):
return 'Empty String'
else:
return new_string
Here is an example of output for which it does not work.
print(super_reduced_string('abab'))
It outputs 'Empty String' but should output 'abab'.
By using a counter, your program loses track of the order in which it saw characters. By example with input 'abab', you program sees two a's and two b's and deletes them even though they are not adjacent. It then outputs 'Empty String' but should output 'abab'.
O(n) stack-based solution
This problem is equivalent to finding unmatched parentheses, but where an opening character is its own closing character.
What this means is that it can be solved in a single traversal using a stack.
Since Python can return an actual empty string, we are going to output that instead of 'Empty String' which could be ambiguous if given an input such as 'EEEmpty String'.
Code
def super_reduced_string(s):
stack = []
for c in s:
if stack and c == stack[-1]:
stack.pop()
else:
stack.append(c)
return ''.join(stack)
Tests
print(super_reduced_string('aaabab')) # 'abab'
print(super_reduced_string('aabab')) # 'bab'
print(super_reduced_string('abab')) # 'abab'
print(super_reduced_string('aaabccddd ')) # 'abd'
print(super_reduced_string('baab ')) # ''
I solved it with recursion:
def superReducedString(s):
if not s:
return "Empty String"
for i in range(0,len(s)):
if i < len(s)-1:
if s[i] == s[i+1]:
return superReducedString(s[:i]+s[i+2:])
return s
This code loops over the string and checks if the current and next letter/position in the string are the same. If so, these two letters/positions I get sliced from the string and the newly created reduced string gets passed to the function.
This occurs until there are no pairs in the string.
TESTS:
print(super_reduced_string('aaabccddd')) # 'abd'
print(super_reduced_string('aa')) # 'Empty String'
print(super_reduced_string('baab')) # 'Empty String'
I solved it by creating a list and then add only unique letters and remove the last letter that found on the main string. Finally all the tests passed!
def superReducedString(self, s):
stack = []
for i in range(len(s)):
if len(stack) == 0 or s[i] != stack[-1]:
stack.append(s[i])
else:
stack.pop()
return 'Empty String' if len(stack) == 0 else ''.join(stack)
I used a while loop to keep cutting down the string until there's no change:
def superReducedString(s):
repeat = set()
dups = set()
for char in s:
if char in repeat:
dups.add(char + char)
else:
repeat.add(char)
s_old = ''
while s_old != s:
s_old = s
for char in dups:
if char in s:
s = s.replace(char, '')
if len(s) == 0:
return 'Empty String'
else:
return s

Robber's language backwards?

does anyone know how to translate robber's languge to English in python?
like this one but in reverse?
def translate(s):
consonants = 'bcdfghjklmnpqrstvwxz'
return ''.join(a + 'o' + a if a in consonants else a for a in s)
print(translate("hej"))
Maybe something like:
def translate(s):
consonants = 'bcdfghjklmnpqrstvwxz'
counter = 0
outputcounter = 0
output = s
while counter < len(s):
char = s[counter]
if char in consonants:
output = output[:outputcounter] + char + output[outputcounter + 3:]
counter += 3
outputcounter += 1
else:
counter += 1
outputcounter += 1
return output
Try it out! (I don't know if that's nice code style, but however)
Here is an alternative approach
Since this is an interesting problem, I decided to have a go myself. Here is an efficient way of writing your first function with O(1) set lookup:
def translate_english_robber(s):
consonants = 'bcdfghjklmnpqrstvwxz'
# using a set instead is more efficient
lookup = set(consonants + consonants.upper())
result = ""
for char in s:
if char in lookup:
# anonymous function for converting the case of the letter "o"
convert_case = lambda x: "o" if x.islower() else "O"
# add it to the result
result += char + convert_case(char) + char
else:
result += char
return result
Then for the reverse translation, all you need to do is find a consonant, and append it to the list, then somehow remove the next 2 characters, and continue the next iteration after the last removed character. Otherwise, if the current character is not a constant, add it normally.
For example, If my Robbers language was "hohey", I would first find "h", add it, and remove "o" and "h" after that, then start iterating from "e". In the end, we would have "hey" as the English translation.
Using an iterator would be useful here. You can also read up on iterators here, they are quite useful for problems like this.
Here is my attempt:
def translate_robber_english(s):
consonants = 'bcdfghjklmnpqrstvwxz'
lookup = set(consonants + consonants.upper())
# create the iterator
it = iter(list(s))
result = ""
# loop till we reach the end
while True:
try:
# get the current letter
current = next(it)
# add it regardless
result += current
# if consonant, skip the next to letters
if current in lookup:
next(it)
next(it)
# If this exception occurs, break out of the loop
except StopIteration:
break
return result
And now you can get the reverse translations with both the above functions:
>>> robber = translate_english_robber("black")
>>> print(robber)
boblolacockok
>>> english = translate_robber_english(robber)
>>> print(english)
black
You can try something like this:
def reverse_translate(s):
vowel = ['a', 'e', 'i', 'o', 'u']
final = []
for i in range(len(s)):
if s[i] in vowel:
final.append(s[i])
else:
try:
if s[i] == s[i + 2]:
final.append(s[i:i + 3])
except IndexError:
pass
for j, i in enumerate(final):
if i == 'o':
try:
if final[j] == final[j + 1]:
pass
else:
del final[j]
except IndexError:
del final[j]
return "".join(list(map(lambda x: x[0], final)))
Now test_cases:
Normal test_case:
print(reverse_translate('boblolacockok'))
output:
black
But if text also include 'o' as vowel now :
print(reverse_translate('boblolocockok'))
output:
block

Swapping uppercase and lowercase in a string [duplicate]

This question already has answers here:
How can I invert (swap) the case of each letter in a string?
(8 answers)
How can I use `return` to get back multiple values from a loop? Can I put them in a list?
(2 answers)
Closed 6 months ago.
I would like to change the chars of a string from lowercase to uppercase.
My code is below, the output I get with my code is a; could you please tell me where I am wrong and explain why?
Thanks in advance
test = "AltERNating"
def to_alternating_case(string):
words = list(string)
for word in words:
if word.isupper() == True:
return word.lower()
else:
return word.upper()
print to_alternating_case(test)
If you want to invert the case of that string, try this:
>>> 'AltERNating'.swapcase()
'aLTernATING'
There are two answers to this: an easy one and a hard one.
The easy one
Python has a built in function to do that, i dont exactly remember what it is, but something along the lines of
string.swapcase()
The hard one
You define your own function. The way you made your function is wrong, because
iterating over a string will return it letter by letter, and you just return the first letter instead of continuing the iteration.
def to_alternating_case(string):
temp = ""
for character in string:
if character.isupper() == True:
temp += character.lower()
else:
temp += word.upper()
return temp
Your loop iterates over the characters in the input string. It then returns from the very first iteration. Thus, you always get a 1-char return value.
test = "AltERNating"
def to_alternating_case(string):
words = list(string)
rval = ''
for c in words:
if word.isupper():
rval += c.lower()
else:
rval += c.upper()
return rval
print to_alternating_case(test)
That's because your function returns the first character only. I mean return keyword breaks your for loop.
Also, note that is unnecessary to convert the string into a list by running words = list(string) because you can iterate over a string just as you did with the list.
If you're looking for an algorithmic solution instead of the swapcase() then modify your method this way instead:
test = "AltERNating"
def to_alternating_case(string):
res = ""
for word in string:
if word.isupper() == True:
res = res + word.lower()
else:
res = res + word.upper()
return res
print to_alternating_case(test)
You are returning the first alphabet after looping over the word alternating which is not what you are expecting. There are some suggestions to directly loop over the string rather than converting it to a list, and expression if <variable-name> == True can be directly simplified to if <variable-name>. Answer with modifications as follows:
test = "AltERNating"
def to_alternating_case(string):
result = ''
for word in string:
if word.isupper():
result += word.lower()
else:
result += word.upper()
return result
print to_alternating_case(test)
OR using list comprehension :
def to_alternating_case(string):
result =[word.lower() if word.isupper() else word.upper() for word in string]
return ''.join(result)
OR using map, lambda:
def to_alternating_case(string):
result = map(lambda word:word.lower() if word.isupper() else word.upper(), string)
return ''.join(result)
You should do that like this:
test = "AltERNating"
def to_alternating_case(string):
words = list(string)
newstring = ""
if word.isupper():
newstring += word.lower()
else:
newstring += word.upper()
return alternative
print to_alternating_case(test)
def myfunc(string):
i=0
newstring=''
for x in string:
if i%2==0:
newstring=newstring+x.lower()
else:
newstring=newstring+x.upper()
i+=1
return newstring
contents='abcdefgasdfadfasdf'
temp=''
ss=list(contents)
for item in range(len(ss)):
if item%2==0:
temp+=ss[item].lower()
else:
temp+=ss[item].upper()
print(temp)
you can add this code inside a function also and in place of print use the return key
string=input("enter string:")
temp=''
ss=list(string)
for item in range(len(ss)):
if item%2==0:
temp+=ss[item].lower()
else:
temp+=ss[item].upper()
print(temp)
Here is a short form of the hard way:
alt_case = lambda s : ''.join([c.upper() if c.islower() else c.lower() for c in s])
print(alt_case('AltERNating'))
As I was looking for a solution making a all upper or all lower string alternating case, here is a solution to this problem:
alt_case = lambda s : ''.join([c.upper() if i%2 == 0 else c.lower() for i, c in enumerate(s)])
print(alt_case('alternating'))
You could use swapcase() method
string_name.swapcase()
or you could be a little bit fancy and use list comprehension
string = "thE big BROWN FoX JuMPeD oVEr thE LAZY Dog"
y = "".join([val.upper() if val.islower() else val.lower() for val in string])
print(y)
>>> 'THe BIG brown fOx jUmpEd OveR THe lazy dOG'
This doesn't use any 'pythonic' methods and gives the answer in a basic logical format using ASCII :
sentence = 'aWESOME is cODING'
words = sentence.split(' ')
sentence = ' '.join(reversed(words))
ans =''
for s in sentence:
if ord(s) >= 97 and ord(s) <= 122:
ans = ans + chr(ord(s) - 32)
elif ord(s) >= 65 and ord(s) <= 90 :
ans = ans + chr(ord(s) + 32)
else :
ans += ' '
print(ans)
So, the output will be : Coding IS Awesome

Categories

Resources