Getting two different values from a recursive function? - python

I am trying to create a function in python that splits a string in to two strings, where the first one have all the lower case letters + some other special characters and the second one having all the upper case letters + special characters.
The point is to be able to type:
>>> first_message,second_message=string_split("SomEChaRacTers")
>>> print(first_message, second_message)
to get the result printed.
This is what i have right now:
def string_split(string):
first_message_signs = "_."
second_message_signs = " |"
one = ""
two = ""
if len(string) == 0:
return string
if string[0].islower() or string[0] in first_message_signs:
one += string[0] + string_split(string[1:])
return one
elif string[0].isupper() or string[0] in second_message_signs:
two += string[0] + string_split(string[1:])
return two
else:
return string_split(string[1:])
I am getting this error when making the first call in the prompt:
Traceback (most recent call last):
File "", line 1, in
ValueError: too many values to unpack (expected 2)
When i try with only message_one i get all the characters in one string.
What should i do?

Your first line
first_message,second_message=string_split("SomEChaRacTers")
expects string_split to return two values. However, your function only ever returns one.
What you want is
def string_split(string):
first_message_signs = "_."
second_message_signs = " |"
one = ""
two = ""
if len(string) == 0:
return one, two
if string[0].islower() or string[0] in first_message_signs:
one += string[0]
elif string[0].isupper() or string[0] in second_message_signs:
two += string[0]
ret1, ret2 = string_split(string[1:])
one += ret1
two += ret2
return one, two
On a side note, there's no compelling reason for string_split to be recursive. Try this:
def string_split(string):
first_message_signs = "_."
second_message_signs = " |"
one = ''.join(c for c in string if c.islower() or c in first_message_signs)
two = ''.join(c for c in string if c.isupper() or c in second_message_signs)
return one, two

Related

How to return the middle character of a string in python? [duplicate]

This question already has answers here:
Return middle part of string
(2 answers)
Closed 1 year ago.
Full problem:
Write a function named mid that takes a string as its parameter. Your function should extract and return the middle letter. If there is no middle letter, your function should return the empty string. For example, mid("abc") should return "b" and mid("aaaa") should return "".
Question:
How come at the very end print(x) and everything works as expected, but return x breaks the program with the following:
IndexError: list index out of range
import math
def mid(string):
enum = list(enumerate(string))
lastnum = enum[-1][0] + 1
if lastnum % 2 == 0:
return ""
else:
middle = math.floor(len(enum)/2)
x = enum[middle][1]
print(x)
return x
mid("asaba")
Here's an example of how I would approach it:
def mid(string):
if len(string) % 2 == 0:
return ""
else:
offset = int(len(string) / 2)
return string[offset: offset + 1]
mid("abc")
mid("asaba")
Your code fails on edge cases, specifically when given the empty string, but I found during my tests that it works for strings like "asaba", "aaaa", and "abc" but throws the error when given "". The reason for this is because lastnum = enum[-1][0] + 1 will give an index that does not exist for the empty string. The way to fix this would be to add a condition at the beginning of your function that checks if it's an empty string, so like this:
if len(string) == 0:
return ""
import math
def mid(string_1):
string_2 = ''
if len(string_1) %2 == 0:
return string_2
else:
string_2 = string_1[math.floor(len(string_1)/2)]
return string_2
print(mid("abc"))
I've done the function in this way and it works fine, the logic is the following:
If the length of the string is even return an empty string ""
If the length of the string is odd then returns the middle character, this is done by finding the index in the middle:
string_2 = string_1[math.floor(len(string_1)/2)]

Int and str changing every letter with error + EDIT: zero indexing eachword

My goal is to write a function which change every even letter into upper letter and odd to lower (space also count as a one element).
This is my code
def to_weird_case(s):
for i in s:
if len(i) % 2 == 0:
s[i] = i.upper() + s(i+1)
else:
s[i] = i.lower() + s(i+2)
return i
I think it should be quite correct, but it gives me error.
line 7, in to_weird_case
s[i] = i.lower() + s(str(i)+2)
TypeError: must be str, not int
EDIT:
I have a sugesstion but I don't know how to make it. I try it for myself and back here.
This needs to definitly explicietly state that the zero indexing uppercase is for each word.
Do you know guys how to make it?
So we can analyze your code and just explain what you typed:
def to_weird_case(s):
for i in s: # s is your string, and i is the actual character
if len(i) % 2 == 0: # if your length of the character can be divided by 2. Hmm this is weird
s[i] = i.upper() + s(i+1) # s[i] change a character in the string but you should provide an index (i) so an integer and not a character. But this is not supported in Python.
else:
s[i] = i.lower() + s(i+2)
return i # This will exit after first iteraction, so to_weird_case("this") will return "t".
So what you need to is first create a output string and fill that. And when iteration over s, you want the index of the char and the char value itself.
def to_weird_case(s):
output = ""
for i, myChar in enumerate(s):
if i % 2 == 0:
output += myChar.upper()
else:
output += myChar.lower()
return output
my_sentence = "abcdef"
print(to_weird_case(my_sentence))
And when you want to ignore spaces, you need to keep track of actual characters (excluding spaces)
def to_weird_case(s):
output = ""
count = 0
for myChar in s:
if myChar.isspace():
output += myChar
else:
if count % 2 == 0:
output += myChar.upper()
else:
output += myChar.lower()
count += 1
return output
my_sentence = "abc def"
print(to_weird_case(my_sentence))
Test this yourself
def to_weird_case(s):
for i in s:
print (i)
After doing this you will find that i gives you characters.
if len(i) % 2 == 0:
This line is incorrect as you are trying to find the length of a single character. len(s) would be much better.
So the code will be like
def to_weird_case(s):
s2 = "" #We create another string as strings are immutable in python
for i in range(len(s)):
if i % 2 == 0:
s2 = s2 + s[i].upper()
else:
s2 = s2 + s[i].lower()
return s2
From #RvdK analysis, you'ld have seen where corrections are needed. In addition to what has been pointed out, I want you to note that s[i] will work fine only if i is an integer, but in your case where (by assumption) i is a string you'll encounter several TypeErrors. From my understanding of what you want to do, it should go this way:
def to_weird_case(s):
for i in s:
if s.index(i) % 2 == 0:
s[s.index(i)] = i.upper() + s[s.index(i)]
elif s.index(i) % 2 == 1:
s[s.index(i)] = i.lower() + s[s.index(i)]
return i # or possibly return s
It is possible to do in a single line using a list comprehension
def funny_case(s):
return "".join([c.upper() if idx%2==0 else c.lower() for idx,c in enumerate(s)])
If you want to treat each word separately then you can split it up in to a list of words and "funny case" each word individually, see below code
original = "hello world"
def funny_case(s):
return "".join([c.upper() if idx%2==0 else c.lower() for idx,c in enumerate(s) ])
def funny_case_by_word(s):
return " ".join((funny_case(word) for word in s.split()))
print(funny_case_by_word(original))
Corrected code is as follows
def case(s):
txt=''
for i in range(len(s)):
if i%2==0:
txt+=s[i].upper()
else:
txt+=s[i].lower()
return txt
String assignment gives error in Python therefore i recommend considering my approach
When looping over elements of s, you get the letter itself, not its index. You can use enumerate to get both index and letter.
def to_weird_case(s):
result = ''
for index, letter in enumerate(s):
if index % 2 == 0:
result += letter.upper()
else:
result += letter.lower()
return result
correct code:
def to_weird_case(s):
str2 = ""
s.split() # through splitting string is converted to list as it is easy to traverse through list
for i in range(0,len(s)):
n = s[i] # storing value in n
if(i % 2 == 0):
str2 = str2 + n.upper()
else:
str2 = str2 + n.lower()
return str2
str1 = "hello world"
r = to_weird_case(str1)
print(r)

Given a string S, remove consecutive duplicates from it recursively using python

i am adding str[1] that is causing one repeated element to be left but if donot do that string does not get printed. any solutions
def removeCD(str):
l = len(str)
if l == 0 or l == 1:
return str
if(str[0]==str[1]):
return str[1] + removeCD(str[2:])
else:
return str[0] + removeCD(str[1:])
string = input().strip()
print(removeCD(string))
When characters are equal, you again adding duplicate character. This should work:
def removeCD(str):
l = len(str)
if l == 0 or l == 1:
return str
if(str[0]==str[1]):
return removeCD(str[1:])
else:
return str[0] + removeCD(str[1:])
string = input().strip()
print(removeCD(string))
Here is the case analysis we need to perform -
If string length is less than two (base case), there is nothing to compare, simply return the string
Otherwise (by induction) the string is at least two characters long. If the first matches the second, drop the first letter and return the recursive result
Otherwise (by induction) the string is at least two characters long and the first two characters do not match. Return the first char combined with the recursive result.
This encodes to a python program in a straightforward way -
def remove_adjacent_dupes (s = ""):
if len(s) < 2:
return s
elif s[0] == s[1]:
return remove_adjacent_dupes(s[1:])
else:
return s[0] + remove_adjacent_dupes(s[1:])
print(remove_adjacent_dupes("bookkeeper"))
# bokeper
When the characters are equal, you should be recursing on everything but the first character:
if(str[0]==str[1]):
return removeCD(str[1:])
def remove(string):
l = len(string)
if l==0 or l==1:
return string
if string[0] == string[1]:
s = remove(string[1:])
return s
else:
s = remove(string[1:])
return string[0]+s
string = input().strip()
print(remove(string))

Accepting an empty value in a function

I need to create function that removes dash/underscore and combine the words. however if i use an empty string i get an error string index out of range
I believe whats causing this error is because of the line below. However this is impt in my code since it gets the first letter of my string.
# first_char = text[0]
import re
import string
def to_camel_case(text):
split_chars = []
ans = ''
small = ''
# store the first letter in variable
first_char = text[0]
# use split to separate the phrase given in text
for x in re.split('[-_]',text):
if text == None:
return
else:
ans += x.title()
# combine the vars
if ans[0] != first_char:
small += ans[0].lower()
return small + ans[1:]
else:
return ans
IndexError Traceback (most recent call last)
<ipython-input-64-f8cbc9c16e79> in <module>
----> 1 to_camel_case('')
<ipython-input-61-2bd3248e632d> in to_camel_case(text)
13
14 ## maintain the very first letter to its original form (lower or uppercase) and store it in a var
---> 15 first_char = text[0]
16
17
IndexError: string index out of range
You are trying to read a null value by text[0] as the string is empty. You can always check the input if it is null or have value. If value exist carry on with the operation otherwise return with a response.
Using text[0] needs that text has at least one character. So you must test if text is not empty before.
so this should work, your spacing wasn't good and as well, I've re-done the spacing and fixed your bug. The error was caused because text doesn't have any value when you want to get the first index. It's better to put as much as you can inside the body of the function.
import re
import string
def to_camel_case(text = 'Test'):
split_chars = []
ans = ''
small = ''
first_char = text[0]
# use split to separate the phrase given in text
for x in re.split('[-_]',text):
if text == None:
return
else:
ans += x.title()
# combine the vars
if ans[0] != first_char:
small += ans[0].lower()
return small + ans[1:]
else:
return ans
to_camel_case('StACKoverFLOW')
OUTPUT
Stackoverflow

Function that give the number of words

I'm doing a function that give the number of words in a sentence.
Example: " Hello L World " there are 3 "words" (A letter is counted like a word).
Here is my code:
def number_of_word(s):
"""
str -> int
"""
# i : int
i = 0
# nb_word : int
nb_word = 0
if s == "":
return 0
else:
while i < len(s)-1:
if ((s[i] != " ") and (s[i+1] == " ")):
nb_word = nb_word + 1
i = i + 1
else:
i = i + 1
if s[len(s)-1] != " ":
nb_word = nb_word + 1
return nb_word
else:
return nb_word
I tried my function and I think it works. But, I also think there is a better way to do a function that do the same thing in an easier way.
Can you tell me if you know one better function? Or any comments on mine?
I hade to use:
if s == "":
return 0
else:
...........
because if I didn't, my function didn't work for number_of_word("")
If you define words as character sequences separated by one or more whitespaces, then you can simply use the split method of strings to split to words,
and then len to get their count:
def number_of_word(s):
return len(s.split())
From the documentation (emphasis mine):
split(...) method of builtins.str instance
S.split(sep=None, maxsplit=-1) -> list of strings
Return a list of the words in S, using sep as the delimiter string.
If maxsplit is given, at most maxsplit splits are done. If sep is not
specified or is None, any whitespace string is a separator and empty
strings are removed from the result.
If you want you can use RegExp
import re
def number_of_word(s):
pattern = r'\b\w+\b'
return len(re.findall(pattern, s))
If you can't use split or regex, I think this is the right solution:
def count(sentence):
wlist = []
word = ""
for c in sentence:
if c == " ":
wlist.append(word)
word = ""
else:
word += c
wlist.append(word)
return len(wlist)
You can use split() method :
def count(string1):
string1=string1.split()
return len(string1)
print(count(" Hello L World "))
output:
3
I can't use more python' functions than just "len".
So, I can't use split or RegExp.
So I want to make this function with just basic code and len.
Well, since the requirements were published, here's a way to do this without calling any library functions:
def count_words(sentence):
count, white = 0, True
for character in sentence:
if character not in " \t\n\r":
if white:
count += 1
white = False
else:
white = True
return count

Categories