How to count how many "ZE"s in a given string - python

I am trying to complete this attempt to count how many times "Z" eats "E" in the string. In other words I need to count how many times "ZE" is in the given string:
letters = "GOLDZEZEDUZZEOZBIX"
Why is this code only returning 1?
def is_eaten(data):
count = 0
if "Z" and "E" in data:
count += 1
return count

You can simply use the count method:
letters.count('ZE') # returns 3

Because you set count to one if Z and E is in data. Not once for every ZE, but if.
Read up on for loops.

Why is this code only returning 1?
Multiple reasons.
First, there's no loop in the code, so there's no way it could ever return more than 1.
Second, if "Z" and "E" in data doesn't mean what you think. It's true if "Z" is true, and also "E" in data is true. In other words, it's equivalent to if ("Z") and ("E" in data). But, even if the parentheses went the other way, and it were if ("Z" and "E") in data) it wouldn't work. Since "Z" and "E" is just "E" (try it and see), that would just be checking whether "E" appears in data.
You need if "Z" in data and "E" in data to do what you're trying to do.
Third, even if you fix that, the logic doesn't make any sense. This is true if there's any "Z" anywhere, and any "E" anywhere. So, it would be true for "EZ", which is obviously wrong. You only want it to be true if the substring "ZE" appears in the data, right? You can use if "ZE" in data to mean exactly that. Or, if you're not allowed to do that for some reason, first find a "Z" and check whether the next character is "E".
Here's a way you could do this (not a very good way, but the closest I could come up with to what you tried):
def count_eaten(data):
count = 0
while True:
index = data.find('Z')
if index == -1:
return count
data = data[index+1:]
if data[0] == 'E':
count += 1
Or, more simply:
def count_eaten(data):
count = 0
while True:
index = data.find('ZE')
if index == -1:
return count
data = data[index+1:]
count += 1
Or, even more simply:
def count_eaten(data):
return data.count('ZE')
I'm guessing your professor doesn't want this last one, and probably doesn't want the one before it either… but that's really just a guess (as is the fact that this is homework in the first place).

for even another solution try this:
def keyCount(dataset, key):
return dataset.count(key)
correct usage of this method would then look like:
>>> letters = "GOLDZEZEDUZZEOZBIX"
>>> key = "ZE"
>>> keyCount(letters, key)
3
or
>>> keyCount(letters, "ZE")
3
or
>>> keyCount("GOLDZEZEDUZZEOZBIX", "ZE")
3
etc..

Related

Minimum number of increments/decrements to transform string to a good form?

We are asked to modify a string by performing specific moves on it. Given a string of lowercase English characters ('a' - 'z'), two types of moves can be performed on any index, any number of times:
Decrement the character by 1. The letter 'a' cannot be decremented.
Increment the character by 1. Letter 'z' cannot be incremented.
Calculate the minimum number of moves required to modify the string to a good form. A good form string is one in which each character is adjacent to at least one equal character.
Example 1:
s = ‘aca’
Output: 2
Explanation: Decrement 'c' twice to get 'aaa'. A minimum of 2 moves is required.
Example 2:
s = 'abcdef'
Output: 3
Explanation: Decrement 'b' by 1 to become 'a'. Increment 'c' by 1 to become 'd'. Increment 'e' by 1 to become 'f'. This gets us "aaddff".
The first and last characters of the string only have one adjacent neighbor, and so they must be equal to that adjacent character.
What would be the best way to go about this?
I initially thought using two pointers, one for the left/start and right/end indices, and slowly moving them towards the center would be the best approach, using the thought that the edge of the string must be equal to the inner character in order to become equal.
But this doesn't give us a globally optimal solution. Would the best approach be something related to dynamic programming? If so, how would that look?
Yes, there’s a dynamic program, which can be extracted straightforwardly
from an algorithm that verifies a solution, implemented below in Python.
def has_good_form(s):
previous_letter = None
needs_adjacent_copy = False
for letter in s:
if letter == previous_letter:
needs_adjacent_copy = False
elif not needs_adjacent_copy:
previous_letter = letter
needs_adjacent_copy = True
else:
return False
return not needs_adjacent_copy
print(has_good_form("aca"))
print(has_good_form("aaa"))
print(has_good_form("abcdef"))
print(has_good_form("aaddff"))
has_good_form() remembers the previous letter and whether it is known
to have an adjacent copy, for a total of 26×2 = 54 states, plus the
starting state (so 55). The idea of the dynamic program is, for each
state and time, what’s the cheapest set of modifications that will put
has_good_form() in that state at that time? That looks something like
this (untested).
import collections
import math
import string
def distance(a, b):
return abs(ord(a) - ord(b))
def cheapest_good_form(s):
state_to_min_cost = {(None, False): 0}
for original_letter in s:
options = collections.defaultdict(list)
for state, min_cost in state_to_min_cost.items():
previous_letter, needs_adjacent_copy = state
for letter in string.ascii_lowercase:
cost = min_cost + distance(original_letter, letter)
if letter == previous_letter:
options[(letter, False)].append(cost)
elif not needs_adjacent_copy:
options[(letter, True)].append(cost)
state_to_min_cost = {state: min(costs) for (state, costs) in options.items()}
return min(
(
cost
for (
(_, needs_adjacent_copy),
cost,
) in state_to_min_cost.items()
if not needs_adjacent_copy
),
default=math.inf,
)
print(cheapest_good_form(""))
print(cheapest_good_form("a"))
print(cheapest_good_form("aca"))
print(cheapest_good_form("abcdef"))

HackerRank Game of Thrones

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]

Write a function that takes a string as an argument and displays the letters, one per line using loops in python

I'm learning to program and I'm using "how to think like an computer scientist" the above question is an exercise
This is the program without a function
fruit = "banana"
index = 0
while index < len(fruit):
letter = fruit[index]
print(letter)
index = index + 1
I want to put that into a function like
def tranversal(fruit):
index = 0
while index < len(fruit):
letter = fruit[index]
return letter
index += 1
print(tranversal("apple"))
However this is only printing the first letter of "apple" and if I use print statement instead of return I will get None.
I'm very confused and need help !!
Seems like you didn't understand the purpose of the return statement inside a function. You might want to read this answer first to make things clear.
Once you understand the difference between print() and return, you should define what your function needs to do. Does it need to return the answer or is printing it on the screen enough?
Assuming the latter, given that strings are iterable, a more pythonic way to do it would be:
def transversal(fruit):
for letter in fruit:
print(letter)
Note that since the function is not explicitly returning a value if you try something like:
foo = transversal("banana")
the variable foo will hold the value None.
If you want your function to return the answer and not print it, you could append each letter to an empty result string, with separators for each new line and after you are done with that, simply return result. It could be a good exercise, so you should give it a try :).
A simple solution:
print(*'banana', sep='\n')
Output:
b
a
n
a
n
a
With help of the star operator * you can split a list or a string into parts and and pass them as multiple arguments to function. So the expression print(*'abc') is equivalent to print('a', 'b', 'c').
If you use print in the function, then you dont need to use print when calling the function.
def tranversal(fruit):
index = 0
while index < len(fruit):
letter = fruit[index]
print(letter)
index += 1
tranversal("apple")
If you use a return statement inside of the while loop, then you will immediately leave the function (and return the first letter), and the while loop will not be executed for higher indices.
You can use this code snippet
def printAllChar(s):
for i in s:
print(i,end='\n')
//calling here...
printAllChar("ProgRank")
//output here...
P
r
o
g
R
a
n
k
For the purpose of understanding i wanted to do that exercise with a function, while loop and get a return value.
I've gotten help and i appreciate everyone, here is my code:
def `tranversal`(fruit):
result = ""
length = int(len(fruit))
index = 0
while index < length:
result += fruit[index]
index += 1
if index == length:
return "\n".join(result)
print(tranversal("string"))
You need to execute the statement using the function outside the function. Just shift return tranversal("apple") outside the function transversal like this:
def transversal(fruit):
index = 0
letters = ''
while index < len(fruit):
letters += fruit[index] + '\n'
index += 1
return letters
print(transversal("apple"))
Thank you #MykolaZotko for pointing out an error in the code that caused it to only print the first letter.

How does comparing two chars (within a string) work in Python

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.

Replace multiple characters in a string with one from a generator

I'm looking for a way to take a string that looks like the following:
(a,1),(b,1),(a,1),(b,5),(a,1),(b,2),(a,1),(b,1),(a,2),(b,6),(a,2)
And replace the first "a" with an even number, the second with the next
up even number, and so on for however long the string is. Then I'd like to take the first "b" and assign it an odd number, then the next "b" gets the
next highest odd number, and so on for however long the string is. I'm
working primarily in Python 2.7, but would be willing to look into other languages if a solution exists in that.
The following regular expression substitution should work:
import re
def odd_even(x):
global a,b
if x.group(1) == 'a':
a += 2
return str(a)
else:
b += 2
return str(b)
a = 0
b = -1
source = "(a,1),(b,1),(a,1),(b,5),(a,1),(b,2),(a,1),(b,1),(a,2),(b,6),(a,2)"
print re.sub("([ab])", odd_even, source)
This prints:
(2,1),(1,1),(4,1),(3,5),(6,1),(5,2),(8,1),(7,1),(10,2),(9,6),(12,2)
even = 2
while "a" in string:
string = string.replace("a", str(even), 1)
even += 2
odd = 1
while "b" in string:
string = string.replace("b", str(odd), 1)
odd += 2

Categories

Resources