: 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"
Related
My goal is to concatenate two strings using recursion.
The input would be str1 = ("long string") str2 = ("yes so long")
and the output would be: 'lyoensg ssto rlionngg'
Assumptions are that both strings are the same length.
My code as of now is:
def concat_order(str1, str2):
if len(str1) == 0:
return 'complete'
i = 0
new_str = str1[i] + str2[i]
i = i + 1
return concat_order(str1[1:], str2[1:])
return new_str
print(concat_order("long string"', "yes so long"))
Im sure Im no where close but I am struggling with making it loop.
I am not allowed to use loops but I can use if statements
You don't need to pass 'i' like this: new_str = str1[i] + str2[i]
as you are already returning string excluding previous character: return concat_order(str1[1:], str2[1:]).
Also a function can not have two return statements like this:
return concat_order(str1[1:], str2[1:])
return new_str
any statement after return statement won't execute. That's why we write multiple return statements in some conditional statement like if else
Modified your program to give the correct answer.
def concat_order(str1, str2, new_str):
if len(str1) == 0:
return new_str
new_str += str1[0] + str2[0]
return concat_order(str1[1:], str2[1:], new_str)
ans = ""
print(concat_order("long string", "yes so long", ans))
or you can do this:
def concat_order(str1, str2):
if len(str1) == 0:
return ''
return str1[0] + str2[0] + concat_order(str1[1:], str2[1:])
print(concat_order("long string", "yes so long"))
as the control flow reaches base case, we already have what we wanted so don't return anything.
Recursion just needs a base case and a recursion case. Here your base case is a little strange. You never want the string "complete" so you shouldn't return that. The base case when str1 is empty should just return the empty string.
Then you just need to take the first letter from each string, concat, and concat with recursion of the rest:
def concat_order(str1, str2):
if len(str1) == 0:
return ''
a, b = str1[0], str2[0]
return a + b + concat_order(str1[1:], str2[1:])
concat_order("long string", "yes so long")
# 'lyoensg ssot rlionngg'
Note the extra space is the correct behavior unless there's a requirement to prevent them.
def concat_strings_rec(str1, str2):
if len(str1) < 1:
return ""
else:
curStr = str1[0] + str2[0]
return curStr + concat_strings_rec(str1[1:], str2[1:])
def concat_string_iter(str1, str2):
return "".join([str1[i] + str2[i] for i in range(len(str1))])
string1 = "long string"
string2 = "yes so long"
print(concat_strings_rec(string1, string2))
print(concat_string_iter(string1, string2))
Expected output:
lyoensg ssot rlionngg
lyoensg ssot rlionngg
Recursive solution
You need the base case which is when the array length is 0. In that case return an empty string. In all other cases return the first element of each string concatenated with the return value of the recursive call to concat_strings_rec(). Remember to decrease the array size for the recursive calls!
Iterative solution
The iterative solution just loops through the array concatenating each character within the two strings and putting the concatenated first, second, third,... character in an array. Then use "".join() to concatenate those two character strings in the array to a complete string.
Recommendation
Don't use the recursive solution as it just consumes more memory due to the call stack and it will be slower and since Python has a limit on the number of calls on the call stack it will fail for larger strings.
I am trying to figure out an easy leetcode question and I do not know why my answer does not work.
Problem:
Write a function to find the longest common prefix string amongst an array of strings.
If there is no common prefix, return an empty string "".
My Code:
shortest=min(strs,key=len)
strs.remove(shortest)
common=shortest
for i in range(1,len(shortest)):
comparisons=[common in str for str in strs]
if all(comparisons):
print(common)
break
else:
common=common[:-i]
The above trial does not work when the length of the strings in the list are same but works for other cases.
Thank you very much.
Friend, try to make it as 'pythonic' as possible. just like you would in real life.
in real life what do you see? you see words and maybe look for the shortest word and compare it to all the others. Okay, let's do that, let's find the longest word and then the shortest.
First we create an empty string, there the characters that are the same in both strings will be stored
prefix = ''
#'key=len' is a necesary parameter, because otherwise, it would look for the chain with the highest value in numerical terms, and it is not always the shortest in terms of length (it is not exactly like that but so that it is understood haha)
max_sentense = max(strings, key=len)
min_sentense = min(strings, key=len)
Okay, now what would we do in real life?
loop both one by one from the beginning, is it possible in python? yes. with zip()
for i, o in zip(max_sentense, min_sentense):
the 'i' will go through the longest string and the 'o' will go through the shortest string.
ok, now it's easy, we just have to stop going through them when 'i' and 'o' are not the same, that is, they are not the same character.
for i, o in zip(max_sentense, min_sentense):
if i == o:
prefix += i
else:
break
full code:
prefix = ''
max_sentense = max(strings, key=len)
min_sentense = min(strings, key=len)
for i, o in zip(max_sentense, min_sentense):
if i == o:
prefix += i
else:
break
print(prefix)
It's quickest to compare the first characters of all the words, and then the second characters, etc. Otherwise you're doing unnecessary comparisons.
def longestCommonPrefix(self, strs):
prefix = ''
for char in zip(*strs):
if len(set(char)) == 1:
prefix += char[0]
else:
break
return prefix
You can do this fairly efficiently in a single iteration over the list. I've made this a little verbose so that it's easier to understand.
import itertools
def get_longest_common_prefix(strs):
longest_common_prefix = strs.pop()
for string in strs:
pairs = zip(longest_common_prefix, string)
longest_common_prefix_pairs = itertools.takewhile(lambda pair: pair[0] == pair[1], pairs)
longest_common_prefix = (x[0] for x in longest_common_prefix_pairs)
return ''.join(longest_common_prefix)
In your code you cross check with the shortest string which can be one of the shortest strings if multiple same length strings are present. Furthermore the shortest might not have the longest common prefix.
This is not a very clean code but it does the job
common, max_cnt = "", 0
for i, s1 in enumerate(strs[:-2]):
for s2 in strs[i+1:]:
for j in range(1, min(len(s1), len(s2))+1):
if s1[:j] == s2[:j]:
if j > max_cnt:
max_cnt = j
common = s1[:j]
This function takes any number of positional arguments.
If no argument is given, it returns "".
If just one argument is given, it is returned.
from itertools import zip_longest
def common_prefix(*strings) -> str:
length = len(strings)
if not length:
return ""
if length == 1:
return strings[0]
# as pointed in another answer, 'key=len' is necessary because otherwise
# the strings will be compared according to lexicographical order,
# instead of their length
shortest = min(strings, key=len)
longest = max(strings, key=len)
# we use zip_longest instead of zip because `shortest` might be a substring
# of the longest; that is, the longest common prefix might be `shortest`
# itself
for i, chars in enumerate(zip_longest(shortest, longest)):
if chars[0] != chars[1]:
return shortest[:i]
# if it didn't return by now, the first character is already different,
# so the longest common prefix is empty
return ""
if __name__ == "__main__":
for args in [
("amigo", "amiga", "amizade"),
tuple(),
("teste",),
("amigo", "amiga", "amizade", "atm"),
]:
print(*args, sep=", ", end=": ")
print(common_prefix(*args))
Simple python code
def longestCommonPrefix(self, arr):
arr.sort(reverse = False)
print arr
n= len(arr)
str1 = arr[0]
str2 = arr[n-1]
n1 = len(str1)
n2 = len(str2)
result = ""
j = 0
i = 0
while(i <= n1 - 1 and j <= n2 - 1):
if (str1[i] != str2[j]):
break
result += (str1[i])
i += 1
j += 1
return (result)
I am trying to make a function that counts all the vowels using recursion and I keep getting string index out of range.
def vowels(s):
vowel = "AEIOUaeiou"
if s == " ":
return 0
if s[0] in vowel:
return 1 + vowels(s[1:])
else:
return vowels(s[1:])
print(vowels("Hello Planet Me"))
I am expecting a number of vowels in a string and I just get error on lines 8 and 10 repeating.
Change this line
if s == " ":
to
if s == "":
or
if len(s) == 0:
or, the best way is to use the boolean value of str type in python which returns a False if the str is empty.
if not s:
For the base case, an empty string is passed to the function and not a space character.
if you just change your initial if condition to
if not s:
return 0
you will be fine. that way you just return 0 if the string is empty an you do not get to the line containing s[1:] (which will raise the error you encountered).
a simple non-recursive way would be:
VOWELS = set("AEIOUaeiou")
def vowels(s):
return sum(char in VOWELS for char in s)
(as True is just an alias for 1 and False is an alias for 0 you can just sum the booleans).
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.
This is my simple code.
def reverseString(aStr):
newStr = ''
if len(aStr) == 0:
return newStr
else:
newStr = newStr + aStr[len(aStr)-1]
return reverseString(aStr[:len(aStr)-1])
For 'alina' (if I insert print newStr before return reverseString...), the output is: newStr='a', newStr='n', newStr='i', newStr='l', newStr='a', newStr=''. I don't get it. Why does it behave like this?
The reason your function has not worked is because you forgot to return newStr at the end. And every time you call your function, newStr will just get reset back to ''.
There's an easier way to do what you are doing. Use slicing:
def reverseString(s):
return s[::-1]
Examples:
>>> reverseString('alina')
'anila'
>>> reverseString('racecar')
'racecar' # See what I did there ;)
Something like this:
def reverseString(aStr, newStr = ''):
if len(aStr) == 0:
return newStr
else:
newStr = newStr + aStr[-1] #-1 returns the last element from the string
return reverseString(aStr[:-1], newStr) #slice the string up to second last char
print reverseString("foobar")
#raboof
The problem with your code is that newStr is getting re-assigned at each recursive loop to an empty string(''), you must pass the newStr value in every recursive call.
def reverseString(aStr, newStr= ''): #define a default value for newStr
if len(aStr) == 0:
return newStr
else:
newStr = newStr + aStr[len(aStr)-1] #better use aStr[-1]
return reverseString(aStr[:len(aStr)-1], newStr) #pass the new value of newStr
print reverseString("foobar")# No value is passed for newStr. So, default is used .
Just sayin', there's an easier way to do this, which avoids recursion and the problems that it entails :
>>> ''.join(reversed("abcd"))
'dcba'
You are returning the result of the recursive call, without keeping the information from previous calls. You have this line:
newStr = newStr + aStr[len(aStr)-1]
but newStr is then discarded.
Possible solution:
def reverseString(aStr):
if len(aStr) == 0:
return ''
else:
return aStr[-1] + reverseString(aStr[:-1])
or simply
def reverseString(s):
return s[-1]+reverseString(s[:-1]) if s else ''
Note that both these solutions are elegant, but are "normal" recursion, and therefore suboptimal; for a tail-recursive solution (which potentially can be optimized into a loop) see #Ashwini Chaudhary's answer.