The problem is formulated as follows:
Write a recursive function that, given a string, checks if the string
is formed by two halves equal to each other (i.e. s = s1 + s2, with s1
= s2), imposing the constraint that the equality operator == can only be applied to strings of length ≤1. If the length of the string is
odd, return an error.
I wrote this code in Python 2.7 that is correct (it gives me the right answer every time) but does not enter that recursive loop at all. So can I omit that call here?
def recursiveHalfString(s):
##param s: string
##return bool
if (len(s))%2==0: #verify if the rest of the division by 2 = 0 (even number)
if len(s)<=1: # case in which I can use the == operator
if s[0]==s[1]:
return True
else:
return False
if len(s)>1:
if s[0:len(s)/2] != s[len(s)/2:len(s)]: # here I used != instead of ==
if s!=0:
return False
else:
return recursiveHalfString(s[0:(len(s)/2)-1]+s[(len(s)/2)+1:len(s)]) # broken call
return True
else:
return "Error: odd string"
The expected results are True if the string is like "abbaabba"
or False when it's like anything else not similat to the pattern ("wordword")
This is a much simplified recursive version that actually uses the single char comparison to reduce the problem size:
def rhs(s):
half, rest = divmod(len(s), 2)
if rest: # odd length
raise ValueError # return 'error'
if half == 0: # simplest base case: empty string
return True
return s[0] == s[half] and rhs(s[1:half] + s[half+1:])
It has to be said though that, algorithmically, this problem does not lend itself well to a recursive approach, given the constraints.
Here is another recursive solution. A good rule of thumb when taking a recursive approach is to first think about your base case.
def recursiveHalfString(s):
# base case, if string is empty
if s == '':
return True
if (len(s))%2==0:
if s[0] != s[(len(s)/2)]:
return False
else:
left = s[1:len(s)/2] # the left half of the string without first char
right = s[(len(s)/2)+1: len(s)] # the right half without first char
return recursiveHalfString(left + right)
else:
return "Error: odd string"
print(recursiveHalfString('abbaabba')) # True
print(recursiveHalfString('fail')) # False
print(recursiveHalfString('oddstring')) # Error: odd string
This function will split the string into two halves, compare the first characters and recursively call itself with the two halves concatenated together without the leading characters.
However like stated in another answer, recursion is not necessarily an efficient solution in this case. This approach creates a lot of new strings and is in no way an optimal way to do this. It is for demonstration purposes only.
Another recursive solution that doesn't involve creating a bunch of new strings might look like:
def recursiveHalfString(s, offset=0):
half, odd = divmod(len(s), 2)
assert(not odd)
if not s or offset > half:
return True
if s[offset] != s[half + offset]:
return False
return recursiveHalfString(s, offset + 1)
However, as #schwobaseggl suggested, a recursive approach here is a bit clunkier than a simple iterative approach:
def recursiveHalfString(s, offset=0):
half, odd = divmod(len(s), 2)
assert(not odd)
for offset in range(half):
if s[offset] != s[half + offset]:
return False
return True
Related
Outline:
Find out if id is acceptable. Acceptable parameters is the sum of the
digits for each part of the id. If each sum is evenly divisible by 10
then the function returns the string "Acceptable", otherwise it
returns the string "Unacceptable".
Example:
isValid('123-12-134') → 'Unacceptable'
isValid('550-55-055') → 'Acceptable'
isValid('123-55-055') → 'Unacceptable'
I've tried converting the entire string into an int, but get some differing results in determining divisible by 10.
My attempted code is:
def isValid(id) :
id=id.replace('-','0')
id=int(id)
if id % 10==0:
return "Valid"
else:
return "Invalid"
Thanks in advance!
You might as well return boolean variables and just compare the output to determine what to print:
def summation(item):
return sum([int(i) for i in item])
def isValid(id_) :
id_part = id_.split('-')
result = [summation(item) % 10 == 0 for item in id_part]
return all(result)
Essentially this loops through all the characters in the split string and determines their sum - 3 sums per provided id.
Then we convert the summed list to a boolean list using your condition of x%10 == 0.
Finally we look at all() the elements of this boolean list to determine if it all True or contains a False.
If all are True then the return of isValid(id_) is True else it is False.
Usage:
ids = ['123-12-134', '550-55-055', '123-55-055']
for id_ in ids:
validity = isValid(id_)
print("Acceptable") if validity else print("Unacceptable")
Output:
Unacceptable
Acceptable
Unacceptable
you mean like this?
sentence = "123-123-123"
a = sum(int(x) for x in sentence if x.isdigit())
Hope this code can help you.
Found on this answer
you mean like this?
sentence = "123-123-123"
a = sum(int(x) for x in sentence if x.isdigit())
return a % 10 == 0
Hope this code can help you.
Found on this answer
We want to short-circuit the 'Unacceptable'.
def isValid(ID):
s = 0
for x in ID:
if x.isdigit():
s += int(x)
else:
if s % 10 == 0:
s = 0
else:
return 'Unacceptable'
return 'Acceptable' if s%10 == 0 else 'Unacceptable'
The solution requires splitting the string into parts using hyphens as separators, which are tested to ensure that the sum of each part's characters is a multiple of 10. The test fails if any of the parts are not a multiple of ten, so each part must be greater than or equal to ten. If any part fails, the string fails, so, there is no need to continue testing if a failed part is found. Acceptable must be returned if the string passes, or Unacceptable if it fails.
This single function solution is easy to read:
def teststring(test):
for part in test.split('-'):
part_failed = int(part)<10
if not part_failed:
sum_chars = 0
for char in part:
sum_chars += int(char)
part_failed = ((sum_chars % 10) != 0)
if part_failed: break
return 'Acceptable' if not part_failed else 'Unacceptable'
This solution uses list comprehension in two functions:
def testpart_comprehended(part):
return ((int(part)>=10) and ((sum(int(char) for char in part) % 10) == 0))
def acceptable_comprehended(test):
return 'Acceptable' if all(testpart_comprehended(part) for part in test.split("-")) else 'Unacceptable'
This solution uses list comprehension in one function:
def all_comprehended(test):
return 'Acceptable' if all(((int(part)>=10) and ((sum(int(char) for char in part) % 10) == 0)) for part in test.split("-")) else 'Unacceptable'
These answers are all too understandable. Please use
isValid = lambda x: (any(sum(map(int, s)) % 10 for s in x.split('-'))
* 'un' + 'acceptable').title()
Unacceptable
for example
>>> isValid('123-123')
'Unacceptable'
>>> isValid('123-127')
'Unacceptable'
>>> isValid('127-127')
'Acceptable'
I have the following code, when going through the python, the options aaabaaaa, zzzazzazz gave me the false test.Here is the code, I am not too sure on how to fix it.
def checkPalindrome(inputString):
n=len(inputString)
#if string is one letter
if n==1:
return True
#if string has more than one letter
for i in range (0, math.floor(n/2)) :
if inputString[i]!=inputString[n-1-i]:
return False
else:
return True
You have a few issues. The main issue here is that your else clause has a return True inside the loop. What you'd want to do is finish iterating over the string before returning True. If you are familiar with boolean logic, this is the equivalent of short circuiting with AND.
The other issue (not really an issue, more a nitpick) is that you can just use integer division //, instead of having to import math's floor function.
So,
def isPalindrome(string):
for i in range(0, len(string) // 2):
if string[i] != string[-(i + 1)]:
return False
return True
Another way of handling this would be using all:
def isPalindrome(string):
return all(x == y for x, y in zip(string, reversed(string)))
Or, taking advantage of python's convenient slice notation for the most concise solution possible, we have:
def isPalindrome(string):
return string == string[::-1]
Try this which uses array slicing (reversing an array of chars)
def checkPalindrome(inputString):
n=len(inputString)
#if string is one letter
if n==1:
return True
#if string has more than one letter
return inputString==inputString[::-1]
Another approach could be using slicing. Strings can be accessed by index like arrays/lists and also be inverted like this.
def isPalindrom(string)
return string == string[::-1]
the [::-1] slicing returns the reversed string, the comparision with the original string is True if it's the same otherwise false.
The purpose of this code is to find the longest string in alphabetical order that occurs first and return that subset.
I can execute the code once, but when I try to loop it I get 'NoneType' object is not iterable (points to last line). I have made sure that what I return and input are all not of NoneType, so I feel like I'm missing a fundamental.
This is my first project in the class, so the code doesn't need to be the "best" or most efficient way - it's just about learning the basics at this point.
s = 'efghiabcdefg'
best = ''
comp = ''
temp = ''
def prog(comp, temp, best, s):
for char in s:
if comp <= char: #Begins COMParison of first CHARacter to <null>
comp = char #If the following character is larger (alphabetical), stores that as the next value to compare to.
temp = temp + comp #Creates a TEMPorary string of characters in alpha order.
if len(temp) > len(best): #Accepts first string as longest string, then compares subsequent strings to the "best" length string, replacing if longer.
best = temp
if len(best) == len(s): #This is the code that was added...
return(s, best) #...to fix the problem.
else:
s = s.lstrip(temp) #Removes those characters considered in this pass
return (str(s), str(best)) #Provides new input for subsequent passes
while len(s) != 0:
(s, best) = prog(comp, temp, best, s)
prog is returning None. The error you get is when you try to unpack the result into the tuple (s, best)
You need to fix your logic so that prog is guaranteed to not return None. It will return None if your code never executes the else clause in the loop.
You don't return in all cases. In Python, if a function ends without an explicit return statement, it will return None.
Consider returning something if, for example, the input string is empty.
so I'm new to programming (and python) and I have to make this program that returns True if the string has zero or one dot characters ("." characters) and return False if the string contains two or more dots
here is what I currently have, I cannot get it to work for me, please correct me if I am wrong, thanks!
def check_dots(text):
text = []
for char in text:
if '.' < 2 in text:
return True
else:
return False
Use the builtin Python function list.count()
if text.count('.') < 2:
return True
It can be even shorter if instead of an if-else statement, you do
return text.count('.') < 2
Also, there are some errors in your function. All you need to do is
def check_dots(text):
return text.count('.') < 2
A correct and shorter version would be:
return text.count('.') <= 1
Python has a function called count()
You can do the following.
if text.count('.') < 2: #it checks for the number of '.' occuring in your string
return True
else:
return False
A shortcut would be:
return text.count('.')<2
Let's analyze the above statement.
in this part, text.count('.')<2: It basically says "I will check for periods that occur less than twice in the string and return True or False depending on the number of occurences." So if text.count('.') was 3, then that would be 3<2 which would become False.
another example. Say you want it to return False if a string is longer than 7 characters.
x = input("Enter a string.")
return len(x)>7
The code snippet len(x)>7 means that the program checks for the length of x. Let's pretend the string length is 9. In this case, len(x) would evaluate to 9, then it would evaluate to 9>7, which is True.
I shall now analyze your code.
def check_dots(text):
text = [] ################ Don't do this. This makes it a list,
# and the thing that you are trying to
# do involves strings, not lists. Remove it.
for char in text: #not needed, delete
if '.' < 2 in text: #I see your thinking, but you can use the count()
#to do this. so -> if text.count('.')<2: <- That
# will do the same thing as you attempted.
return True
else:
return False
I'm working my way through the MIT 6.00 class on OpenCourseWare and I'm having a little trouble with the lecture on recursion. I think I understand the basic idea, that you can break some problems down into smaller, repeatable problems. Where I'm having trouble is understanding how this works in the actual code. There is one specific example that I don't quite understand...
def toChars(s):
import string
s = string.lower(s)
ans = ''
for c in s:
if c in string.lowercase:
ans = ans + c
return ans
def isPal(s):
if len(s) <= 1:
return True
else:
return s[0] == s[-1] and isPal(s[1:-1])
def isPalindrome(s):
"""Returns True if s is a palindrome and False otherwise"""
return isPal(toChars(s))
This code is supposed to check if a string is a palindrome or not. I am a little lost on how isPal(s) works. Here's the steps as I'm reading them...
Check if s is one character or less, if it is return True.
If s has more than one character return a Boolean value (True or False) from the expression comparing the first and last character. So basically check if the first and last letter are the same.
AND return the result of the function run again with the first and last letters stripped from the string.
What is confusing me is the return s[0] == s[-1] and isPal(s[1:-1]) bit. I'm not sure I understand what it means to both return True/False based on the first expression AND return the function. Honestly I'm not even sure what returning the function actually means, I'm guessing it just runs the function again, but doesn't actually return any value. I also don't understand how this can actually tell if a string is a palindrome or not. Wouldn't it just keep hitting the second part of return s[0] == s[-1] and isPal(s[1:-1]) until the string, whether it was a palindrome or not, was reduced to 1 or 0 characters? The only thing I can think of is that returning a false value from return s[0] == s[-1] exits the function with a return of false? But I don't feel like that's actually how Python works, at least in my study so far I haven't run into anything saying that returning a False in a function would prevent the second part of the return statement from executing, which would call the function again regardless of whether the first and last letters where the same.
I'm kind of banging my head against the wall at this point, so any insight would be really appreciated!
Perhaps the best way is to go step by step with the values for that line that is confusing you.
return s[0] == s[-1] and isPal(s[1:-1])
Assuming the String you're testing for is "ABCDBA", here is the sequence of calls
return s[0] == s[-1] and isPal(s[1:-1]) #evaluate to ("A" == "A" and isPal("BCDB")) - need to go deeper
return s[0] == s[-1] and isPal(s[1:-1]) #evaluate ("B" == "B" and isPal("CD")) - need to go deeper
return s[0] == s[-1] and isPal(s[1:-1]) #returns ("C" == "D")
Note that in the last line we didn't evaluate for isPal because of short-circuiting - we know that False and X where X can be True or False is always False. Read more about that here.
At the last line we're 4 functions deep into isPal. Since the last line doesn't require us evaluate for isPal() again, we start "rising to the surface" back to the original invocation of isPal which was at
def isPalindrome(s):
"""Returns True if s is a palindrome and False otherwise"""
return isPal(toChars(s))
One clarification which can help you understand what's going on: return ...X and ...Y means: Compute the value of X. If the value is false, return it, otherwise compute the value of Y, and return it.
More info about the short-circuit, lazy behavior (i.e. not evaluating Y if not needed) of the and and or operators in Python: https://docs.python.org/release/2.7/reference/expressions.html#boolean-operations
So that statement doesn't make the function return two values (X and Y), but one value which is the logical AND of X and Y: it's true iff both X and Y are (evaluated to) true.
Also it's worth distinguishing function from function call. There can be many active calls to the same function, with different arguments, local variables etc., so their return values can also be different (as soon as they return). When a function calls itself, that's called recursion. When a function call returns, execution continues in the caller, which can be the same function (but of course a different, upper-level function call) in case of recursion.
If you run the isPal function on "heeeeh" with print statements:
def isPal(s):
if len(s) <= 1:
return True
else:
print s[0],s[-1]
return s[0] == s[-1] and isPal(s[1:-1])
print isPal("heeeeh")
You get:
h h
e e
e e
True
as each char at index s[0] and s[-1] are equal through each recursive call as the string is a palindrome.
Running it on "aeeee":
def isPal(s):
if len(s) <= 1:
return True
else:
print s[0],s[-1]
return s[0] == s[-1] and isPal(s[1:-1])
print isPal("aeeeeh")
You get :
a h
False
As as soon as s[0] and s-[1] are not equal the functions ends and returns False as it cannot be a palindrome if the chars are not equal.
I'll add my explanation, maybe this will help you.
First things first:
def toChars(s):
import string
s = string.lower(s)
ans = ''
for c in s:
if c in string.lowercase:
ans = ans + c
return ans
will simply take some text and turn it all to lower case, character by character.
Next is:
def isPal(s):
if len(s) <= 1:
return True
else:
return s[0] == s[-1] and isPal(s[1:-1])
To understand this part you ask yourself a question, what is a palindrome and what are ways to know if word or sentence is one.
In this example approach is: palindrome is word or sentence where its characters in same distance from beginning and from the end are the same characters.
So how to check that? Well, first if your word is just one letter or shorter then it's a palindrome.
Then you check if letters at the beginning and the end of your word are the same.
You remember the result as true or false and strip your word from letters you already checked and repeat the process until your word is 1 or less characters long and check if every result of comparison was true.
Example:
Foob->foob
f=b? NO, false
Example 2:
Fbof->fbof
f=f? Yes, true,
bo
b=o? No, false.
true and false = false, so the word is not a palindrome
Example 3:
Fobof->fobof
f=f? Yes, true,
obo,
o=o? Yes, true
b
len(b) = <=1 ? Yes, true,
true and true and true = true, so the word is a palindrome.
Hope it helps, ask if you need more thorough explanation, I'll try to help, no worries, i struggled with recursion at the beginning as well.