Working through exercises on the CodeWars website and I need help being pointed in the right direction for a simple function:
Write a function toWeirdCase (weirdcase in Ruby) that accepts a
string, and returns the same string with all even indexed characters
in each word upper cased, and all odd indexed characters in each word
lower cased. The indexing just explained is zero based, so the
zero-ith index is even, therefore that character should be upper
cased.
The passed in string will only consist of alphabetical characters and
spaces(' '). Spaces will only be present if there are multiple words.
Words will be separated by a single space(' ').
The code I have so far is this:
def to_weird_case(string):
#TODO
new_string = ''
add = 0
for letter in range(len(string)):
if string[letter] == ' ':
add += 1
new_string += string[letter]
continue
if (letter+add)%2 == 0:
new_string += string[letter].upper()
else:
new_string += string[letter].lower()
print("Returning: " + new_string)
return new_string
I am trying to iterate over each letter while taking in to account the spaces but I am unsure how to 'skip over' the spaces and that is what is messing up my function? If someone could point me in the right direction that would be helpful, thanks.
def to_weird_case(string):
#TODO
counter = 0
new_string = ''
add = 0
for letter in range(len(string)):
if string[letter] == ' ':
new_string += string[letter]
continue
if (counter)%2 == 0:
new_string += string[letter].upper()
else:
new_string += string[letter].lower()
# Increment counter after one place as 0th position is even
counter = counter + 1
print("Returning: " + new_string)
return new_string
to_weird_case("HELLO MY NAME IS abcdefghijk")
Output : Returning: HeLlO mY nAmE iS aBcDeFgHiJk
Just create a counter (an integer variable) that will keep track of whether you are in an even or odd index. The counter will not increment if you encounter a space, thereby ignoring it.
def to_weird_case(string):
#TODO
counter = 0
new_string = ''
add = 0
for letter in range(len(string)):
if string[letter] == ' ':
new_string += string[letter]
continue
# Increment counter only if not space
counter = counter + 1
if (counter)%2 == 0:
new_string += string[letter].upper()
else:
new_string += string[letter].lower()
print("Returning: " + new_string)
return new_string
You can disregard the spaces by first splitting the string using str.split, transform each word using enumerate to select even and odd characters, and then rejoin the string using str.join on spaces:
def transform_word(s):
return ''.join(x.upper() if i%2==0 else x.lower() for i, x in enumerate(s))
# ^------------^-> ternary operator for alternating
def to_weird_case(string):
return ' '.join(transform_word(s) for s in string.split())
print(to_weird_case('This is a lovely day'))
# ThIs Is A LoVeLy DaY
And if you eventually want to consider the spaces, use the transform_word function directly:
print(transform_word('This is a lovely day'))
# ThIs iS A LoVeLy dAy
Try list comprehension:
def my_func(your_string):
x = [ x.upper() if i%2==0 else x.lower() for i,x in enumerate(your_string)]
return ''.join(x)
your_string = 'hello my name is lmurdock12'
print(my_func(your_string))
Output:
HeLlO My nAmE Is lMuRdOcK12
So basically what happens in this list comprehension is that we use enumerate()
x = [ x.upper() if i%2==0 else x.lower() for i,x in enumerate(your_string)]
enumerate takes a iterable (string,list..etc) and gives out items one by one (i) where i would be 0,1,2,3...and so on
So in the list comprehension we check if i corresponding to that item x returned from iterable string your_list. So in hello my name is lmurdock12 i would be 0 for h and 1 for e and so on. If i%2==0 which means it's even we keep x.upper() else we keep x.lower() in the list.
Finally use ''.join(x) to join the list and return it if you want.
NOTE: This could be done without enumerate by using index() but that would make our algorithm a little inefficient because that we way we have search for the value and return index everytime. It's better to use enumerate.
Here is a working solution. Hope that helps!
def to_weird_case(string)
words = string.split(" ")
words.map do |word|
word.chars.map.with_index {|letter, idx| idx.even? ? letter.upcase : letter.downcase }.join("")
end.join(" ")
end
You can avoid the counter if you user the enumerate function
def to_weird_case(string):
#TODO
new_string = ''
for i,letter in enumerate(string):
if string[i] == ' ':
new_string += string[i]
continue
if i%2 == 0:
new_string += string[i].upper()
else:
new_string += string[i].lower()
print("Returning: " + new_string)
return new_string
Your code is not really pythonesque. Your function can actually have only 1 line of code. This is why Python is so cool.
def ToWeirdCase(word):
return ''.join([char.upper() if pos%2==0 else char.lower() for pos, char in enumerate(word)])
Hi I had this same problem early this morning, this is my answer:
def to_weird_case(sentence):
counter = 0 # Counter set to zero, because of the even number fact at zero-ith.
weird_sentence = "" # This is the string we are going to return at the end.
for character in sentence:
if character == " " and counter % 2 == 0:
weird_sentence += character
counter += 1 # Incrementation that will now make each characters before a space to be uppercased.
elif character != " " and counter % 2 == 0:
weird_sentence += character.upper()
else:
weird_sentence += character.lower()
counter += 1
return weird_sentence
I hope it helps you out.
Related
I wrote a function which takes a string and gives back the count of small letters and the count of capital letters in that string. The program works for single word but as soon I add two words containing 'space' in between two words, messes things up. spaces counts too.
What is your thoughts?
def myfunc(s):
s = str(s)
upperl = 0
lowerl = 0
for i in s:
if i == i.lower():
lowerl += 1
if i == i.upper():
upperl += 1
if i == ' ':
continue
return upperl,lowerl
x = myfunc('hello G')
print (x)
from the word 'hello G' we expect upper letter and lower letter
count as 1,5 but that space between two words makes it 2,6.
The problem is that ' ' == ' '.upper() and ' ' == ' '.lower() are both true, and you're not checking whether you're currently dealing with an alphanumeric character or something else. Instead, you can check whether you're working with a lowercase letter or an uppercase letter.
Try this:
def calculate_case_count(string: str):
string = str(string)
upper_letter_count = 0
lower_letter_count = 0
for letter in string:
if letter.islower():
lower_letter_count += 1
elif letter.isupper():
upper_letter_count += 1
return upper_letter_count, lower_letter_count
result = calculate_case_count('hello G ')
print(result) # (1, 5)
Using regex will be cleaner solution here
import re
def count_letter_cases(text):
n_lower = len(re.findall("[a-z]", text))
n_upper = len(re.findall("[A-Z]", text))
return n_lower, n_upper
print(count_letter_cases("Hello Goat"))
## Result: (7,2)
from collections import Counter
def count_cases(strng):
counts = Counter(strng)
upper = 0
lower = 0
for char, count in counts.items():
if char.isupper():
upper += count
elif char.islower():
lower += count
return (upper, lower)
Edit: Removed string module. Using internal islower and isupper methods.
I'm working on an assignment and have gotten stuck on a particular task. I need to write two functions that do similar things. The first needs to correct capitalization at the beginning of a sentence, and count when this is done. I've tried the below code:
def fix_capitalization(usrStr):
count = 0
fixStr = usrStr.split('.')
for sentence in fixStr:
if sentence[0].islower():
sentence[0].upper()
count += 1
print('Number of letters capitalized: %d' % count)
print('Edited text: %s' % fixStr)
Bu receive an out of range error. I'm getting an "Index out of range error" and am not sure why. Should't sentence[0] simply reference the first character in that particular string in the list?
I also need to replace certain characters with others, as shown below:
def replace_punctuation(usrStr):
s = list(usrStr)
exclamationCount = 0
semicolonCount = 0
for sentence in s:
for i in sentence:
if i == '!':
sentence[i] = '.'
exclamationCount += 1
if i == ';':
sentence[i] = ','
semicolonCount += 1
newStr = ''.join(s)
print(newStr)
print(semicolonCount)
print(exclamationCount)
But I'm struggling to figure out how to actually do the replacing once the character is found. Where am I going wrong here?
Thank you in advance for any help!
I would use str.capitalize over str.upper on one character. It also works correctly on empty strings. The other major improvement would be to use enumerate to also track the index as you iterate over the list:
def fix_capitalization(s):
sentences = [sentence.strip() for sentence in s.split('.')]
count = 0
for index, sentence in enumerate(sentences):
capitalized = sentence.capitalize()
if capitalized != sentence:
count += 1
sentences[index] = capitalized
result = '. '.join(sentences)
return result, count
You can take a similar approach to replacing punctuation:
replacements = {'!': '.', ';': ','}
def replace_punctuation(s):
l = list(s)
counts = dict.fromkeys(replacements, 0)
for index, item in enumerate(l):
if item in replacements:
l[index] = replacements[item]
counts[item] += 1
print("Replacement counts:")
for k, v in counts.items():
print("{} {:>5}".format(k, v))
return ''.join(l)
There are better ways to do these things but I'll try to change your code minimally so you will learn something.
The first function's issue is that when you split the sentence like "Hello." there will be two sentences in your fixStr list that the last one is an empty string; so the first index of an empty string is out of range. fix it by doing this.
def fix_capitalization(usrStr):
count = 0
fixStr = usrStr.split('.')
for sentence in fixStr:
# changed line
if sentence != "":
sentence[0].upper()
count += 1
print('Number of letters capitalized: %d' % count)
print('Edited text: %s' % fixStr)
In second snippet you are trying to write, when you pass a string to list() you get a list of characters of that string. So all you need to do is to iterate over the elements of the list and replace them and after that get string from the list.
def replace_punctuation(usrStr):
newStr = ""
s = list(usrStr)
exclamationCount = 0
semicolonCount = 0
for c in s:
if c == '!':
c = '.'
exclamationCount += 1
if c == ';':
c = ','
semicolonCount += 1
newStr = newStr + c
print(newStr)
print(semicolonCount)
print(exclamationCount)
Hope I helped!
Python has a nice build in function for this
for str in list:
new_str = str.replace('!', '.').replace(';', ',')
You can write a oneliner to get a new list
new_list = [str.replace('!', '.').replace(';', ',') for str in list]
You also could go for the split/join method
new_str = '.'.join(str.split('!'))
new_str = ','.join(str.split(';'))
To count capitalized letters you could do
result = len([cap for cap in str if str(cap).isupper()])
And to capitalize them words just use the
str.capitalize()
Hope this works out for you
: Write a function, named foldStrings(string1, string2) that takes, as arguments, two strings. If
the two strings are equal in length, the function returns a string that is formed by alternating characters in each of the two strings. If the two strings are not equal in length, the function returns the string “The two strings are not
equal in length.”
For example, >>>foldStrings(“abc”, “def”)
should return the string “adbecf” and >>>foldStrings(“a”, “bc”)
should return the string “The two strings are not equal in length.”
This is what I have so far:
def foldStrings(str1, str2):
newStr = ""
counter = 0
if len(str2) == len(str1):
while counter < len(str2):
for element in str1:
for index in str2:
newStr = newStr + element
newStr = newStr + index
counter += 1
return newStr
else:
return "The two Strings are not equal in length"
and it prints this: 's1s2s3s4s5s6a1a2a3a4a5a6n1n2n3n4n5n6t1t2t3t4t5t6o1o2o3o4o5o6s1s2s3s4s5s6'
instead of this:
's1a2n3t4o5s6'
You have unnecessarily complicated the problem with three nested loops, when a single loop is required.
Replace:
while counter < len(str2):
for element in str1:
for index in str2:
newStr = newStr + element
newStr = newStr + index
counter += 1
return newStr
With:
for index in range(len(str1)) :
newStr = newStr + str1[index] + str2[index]
return newStr
In the original code, if the string length was for example 6, your code says:
Repeat 6 times:
for every character in str1
for every character in str1
do stuff
so that do stuff is executed 6 x 6 x 6 times! You only want to execute it 6 times suggesting a single loop.
What you were doing wrong was not a python specific issue, but rather an issue with your algorithmic and logical thinking. Mathematically the problem suggests a single iteration, while you had three - nested. In this case you might have manually walked through the code or used a debugger to step through it to demonstrate flaw in thinking here.
You can skip using a counter variable by using range
def foldStrings(str1, str2):
if len(str1) != len(str2):
return "The two Strings are not equal in length"
# This should really be a raise ValueError("The two Strings are not equal in length")
newStr = ''
for i in range(len(str1)):
newStr += str1[i] + str2[i]
return newStr
Here's a slightly more compact way to replace the for loop
newStr = ''.join([x for pair in zip(str1, str2) for x in pair])
#Simple way to do it
def foldStrings(str1, str2):
newStr = ""
counter = 0
if len(str2) == len(str1):
while counter < len(str2):
newStr = newStr + str1[counter] + str2[counter]
counter += 1
return newStr
else:
return "The two Strings are not equal in length"
I need to convert a string word where each character that appears only once should be appear as '(' in the new string. Any duplicate characters in the original string should be replaced with ')'.
My code below...
def duplicate_encode(word):
new_word = ''
for char in word:
if len(char) > 1:
new_word += ')'
else:
new_word += '('
return new_word
The test I'm not passing is as follows:
'((((((' should equal '()()()'
This would suggest that, if for example, the input is "recede," the output should read ()()().
Your Code is Good just need some alteration it will be great.
def duplicate_encode(word):
"""
To replace the duplicate letter with ")" in a string.
if given letter is unique it replaced with "("
"""
word_dict = {} # initialize a dictionary
new_word = ""
for i in set(word): # this loop is used to count duplicate words
word_count = word.count(i)
word_dict[i] = word_count # add letter and count of the letter to dictionary
for i in word:
if word_dict[i] > 1:
new_word += ")"
else:
new_word += "("
print new_word
duplicate_encode("recede")
I think you got the answer :)
Just because (it's late and) it's possible:
def duplicate_encode(word):
return (lambda w: ''.join(('(', ')')[c in w[:i] + w[i+1:]] for i, c in enumerate(w)))(word.lower())
print(duplicate_encode("rEcede"))
OUTPUT
> python3 test.py
()()()
>
Seems like your result is based on the number of occurrences of a character in the word, you can use Counter to keep track of that:
def duplicate_encode(word):
from collections import Counter
word = word.lower() # to disregard case
counter = Counter(word)
new_word = ''
for char in word:
if counter[char] > 1: # if the character appears more than once in the word
# translate it to )
new_word += ')'
else:
new_word += '('
return new_word
duplicate_encode('recede')
# '()()()'
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