def is_palindrome(input_string):
# We'll create two strings, to compare them
new_string = input_string.strip()
print(new_string)
# Traverse through each letter of the input string
newstringseperated = new_string.split()
n = len(new_string)
if n%2 == 0:
for i in range(n//2 - 1):
if newstringseperated[i] != newstringseperated[n-1-i]:
print("False")
hello = 1
if hello == 1:
print("False")
else:
print("True")
if (n%2) != 0:
for i in range((n-1)//2):
if newstringseperated[i] != newstringseperated[n-1-i]:
hello2 = 1
if hello2 == 1:
print("False")
else:
print("True")
I tried to execute this code on the words "kayak" and "deed".
It is showing index error for both of them. What is the problem here? Can someone help me find the mistake?
You have a number of problems here. As #John says, you want to use n // 2 - 1 rather than n / 2 - 1 so that the result is an integer. If you use re.sub() instead of split(), you can get rid of whitespace in the middle of your input strings and get rid of tabs as well as spaces. The big issue is that splitting the input string to create newstringseperated and using that is messing you up. If you instead operate on new_string directly, your code will work. Another small detail...you can break as soon as you recognize a mismatch. This version of your code does what I think you're expecting:
import re
def is_palindrome(input_string):
# We'll create two strings, to compare them
new_string = re.sub(r'\s+', '', input_string)
print(new_string)
# Traverse through each letter of the input string
# newstringseperated = new_string.split()
n = len(new_string)
if n % 2 == 0:
hello = 0
for i in range(n // 2 - 1):
if new_string[i] != new_string[n - 1 - i]:
hello = 1
break
if hello == 1:
print("False")
else:
print("True")
# Add any non-blank letters to the
# end of one string, and to the front
# of the other string.
if (n % 2) != 0:
hello2 = 0
for i in range((n - 1) // 2):
if new_string[i] != new_string[n - 1 - i]:
hello2 = 1
break
if hello2 == 1:
print("False")
else:
print("True")
is_palindrome("kayak")
is_palindrome("deed")
is_palindrome("abcde")
is_palindrome("abcd")
Result:
kayak
True
deed
True
abcde
False
abcd
False
It is better to not have the two cases (odd vs even lengths) in your code. Here's a way to have just one version of your inner logic:
import re
def is_palindrome(input_string):
new_string = re.sub(r'\s+', '', input_string)
print(new_string)
# Traverse through each letter of the input string
n = len(new_string)
for i in range(n // 2 - 1 + n % 2):
if new_string[i] != new_string[n - 1 - i]:
hello = 1
break
else:
hello = 0
print("False" if hello == 1 else "True")
This produces the same result.
Just reverse the string and test so no looping needed:
def is_palindrome(txt):
txt = txt.replace(' ', '')
return txt == txt[::-1]
First of all, to delete whitespaces, use replace() instead of strip() as it takes care of whitespaces in the middle of the string as well.
Secondly, the bigger problem is the split() method. It creates a list of substrings based on a specific separator and what you are essentially doing is comparing words instead of characters. Honestly, you don't even need this method to check for palindrome, just modifying the code a bit like this should work fine:
def is_palindrome(input_string):
new_string = input_string.replace(" ", "")
n = len(new_string)
for i in range(n // 2):
if new_string[i] != new_string[n - 1 - i]:
print("False")
return False
print("True")
return True
I had to do this on my phone but this should work if your looking for a palindrome:
txt = "hannah"
txt2 = "kayak"
txt3 = "blaat"
def palin(txt):
first_half = len(txt) // 2
start_second_half = first_half -1 if len(txt)%2==0 else first_half
return txt[:first_half] == txt[-1:start_second_half:-1]
print(palin(txt))
print(palin(txt2))
print(palin(txt3))
Related
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)
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))
With this code, all I am trying to do is insert a dash between odd numbers and an asterisk between even ones. It does not work correctly with every input. It works with, e.g. 46879, but returns None with 468799, or does not insert * between 4 and 6 with 4546793. Why is it doing that? Thanks
def DashInsertII(num):
num_str = str(num)
flag_even=False
flag_odd=False
new_str = ''
for i in num_str:
n = int(i)
if n % 2 == 0:
flag_even = True
else:
flag_even = False
if n % 2 != 0:
flag_odd = True
else:
flag_odd = False
new_str = new_str + i
ind = num_str.index(i)
if ind < len(num_str) - 1:
m = int(num_str[ind+1])
if flag_even:
if m % 2 == 0:
new_str = new_str + '*'
else:
if m % 2 != 0:
new_str = new_str + '-'
else:
return new_str
print DashInsertII(raw_input())
Your function definition is one of the most overbuilt functions I've seen in a while; the following should do what yours was trying to do, sans the complexity.
def DashInsertII(num):
num_str = str(num)
new_str = ''
for i in num_str:
n = int(i)
if n % 2 == 0:
new_str += i + '*'
else:
new_str += i + '-'
return new_str
print DashInsertII(raw_input())
EDIT: I just re-read the question and saw that I misinterpreted what you want, which is to insert a - between two odd numbers and a * between two even numbers. For that, the best solution I can come up with uses regular expressions.
Second Edit: As per alvits's request, I'm including an explanation of the regex in this.
import re
def DashInsertII(num):
num_str = str(num)
# r'([02468])([02468])' performs capturing matches on two even numbers
# that are next to each other
# r'\1*\2' is a string consisting of the first match ([02468]) followed
# by an asterisk ('*') and the second match ([02468])
# example input: 48 [A representation of what happens inside re.sub()]
# r'([02468])([02468])' <- 48 = r'( \1 : 4 )( \2 : 8 )'
# r'\1*\2' <- {\1 : 4, \2 : 8} = r'4*8'
num_str = re.sub(r'([02468])([02468])',r'\1*\2',num_str)
# This statement is much like the previous, but it matches on odd pairs
# of numbers
num_str = re.sub(r'([13579])([13579])',r'\1-\2',num_str)
return num_str
print DashInsertII(raw_input())
If this is still not what you actually want, please comment on this to let me know.
RevanProdigalKnight's answer is almost right but fails when 3 or more even/odd numbers come together.
The right way to do this with regex would be to use positive lookahead (use ?=).
def insert_right_way(num):
#your code here
num_str = str(num)
num_str = re.sub(r'([13579])(?=[13579])', r'\1-', num_str)
num_str = re.sub(r'([02468])(?=[02468])', r'\1*', num_str)
return num_str
def DashInsertII(num):
num_str = str(num)
num_str = re.sub(r'([02468])([02468])',r'\1*\2',num_str)
num_str = re.sub(r'([13579])([13579])',r'\1-\2',num_str)
return num_str
print insert_right_way(234467776667888)
print DashInsertII(234467776667888)
This would output:
234*4*67-7-76*6*678*8*8 ( what is desired)
234*467-776*6678*88 ( not what we wanted)
If I understand your problem - for 11223344 you need 1-12*23-34*4
def DashInsertII(num):
prev_even = ( int(num[0])%2 == 0 )
result = num[0]
for i in num[1:]:
curr_even = (int(i)%2 == 0)
if prev_even and curr_even:
result += '*'
elif not prev_even and not curr_even:
result += '-'
result += i
prev_even = curr_even
return result
print DashInsertII(raw_input())
I'd like to know how do I check if an input is a palindrome with a while loop, using Python.
Thanks:
i tried this
i = 0
n = len(msg_list)
while i < n:
palindrome = msg_list[i]
if palindrome == msg_list[-1]:
print("Palindrome? True")
msg_list.pop(-1)
else:
print("Palindrome? False")
i=i+1
but at the end I receive an error message that the list index is out of range
You don't need to iterate till the end, but only till the middle character. And compare every character to the character at the same index when counted in reverse:
s = "abcca"
length = len(s)
i = 0
while i < length / 2 + 1:
if s[i] != s[-i - 1]:
print "Not Palindrome"
break
i += 1
else:
print "Palidrome"
else part of the while loop is executed, when the loop completes its iteration without any break.
Alternatively, if you can use anything else than a while loop, then this task is just of single line in Python:
if s == s[::-1]:
print "Palindrome"
Oh, it became two lines.
With a while loop
import string
palin = 'a man, a plan, a canal, panama'
def testPalindrome(in_val):
in_val = in_val.lower()
left, right = 0, len(in_val) - 1
while left < right:
char_left, char_right = '#', '#'
while char_left not in string.lowercase:
char_left = in_val[left]
left += 1
while char_right not in string.lowercase:
char_right = in_val[right]
right -= 1
if char_left != char_right:
return False
return True
print testPalindrome(palin)
Without
>>> palindrome = 'a man, a plan, a canal, panama'
>>> palindrome = palindrome.replace(',', '').replace(' ', '')
>>> palindrome
'amanaplanacanalpanama'
>>> d[::-1] == d
True
A short solution using reversed:
for c, cr in s, reversed(s):
if c != cr:
print("Palindrome? False")
break
else:
print("Palindrome? True")
Another way using a while loop. Once two characters don't match, the while loop stops, so it's quite efficient but of course not the best way to do it in Python.
def palindrome(word):
chars_fw = list(word)
chars_bw = list(reversed(word))
chars_num = len(word)
is_palindrome = True
while chars_num:
if chars_fw[chars_num-1] != chars_bw[chars_num-1]:
is_palindrome = False
break
chars_num -= 1
return is_palindrome
Figured I would add another alternative for people still viewing this question. It uses a while loop, and is reasonably concise (although, I still prefer the if word = word[::-1] approach.
def is_palindrome(word):
word = list(word.replace(' ', '')) # remove spaces and convert to list
# Check input
if len(word) == 1:
return True
elif len(word) == 0:
return False
# is it a palindrome....
while word[0] == word[-1]:
word.pop(0)
word.pop(-1)
if len(word) <= 1:
return True
return False
word = "quiniuq"
pairs = zip(word,reversed(word))
a,b = next(pairs)
try:
while a == b:
a,b = next(pairs)
return False # we got here before exhausting pairs
except StopIteration:
return True # a == b was true for every pair
The use of a while loop here is contrived, but it will consume the whole list and perform the test.
If a while loop wasn't a requirement, one would do: all(a == b for a,b in zip(word,reversed(word)))
I was wondering how to reverse two characters in a string.
Here are some examples:
'wing' => 'iwng', 'inwg', 'ingw'
'west' => 'ewst', 'eswt', 'estw'
I was going to use any answers given and put it in a while loop so I can get all the possible combinations of a string while swapping two characters at a time.
ex.
counter = 0
while (counter <= len(str1)):
if str1 == reverse(str2):
return str2
elif str1 == str2
return str2
else:
str1 = *some code that would swap the the characters m and n*
str1 =
n += 1
m += 1
return False
This code compares two strings, str1 to str2, and checks to see if they are the same by swapping the characters around.
ALSO, is there a way i can get this to produce a list of the results instead of printing them?
THANKS!
Try this:
s = 'wing'
s = 'west'
l = [x for x in s]
for i in xrange(len(s)-1):
l[i], l[i+1] = l[i+1], l[i]
print "".join(l)
In order to generate all possibilities, we can use:
s = "yourstring"
for i in range(0,len(s)-2):
if i>0: print s[:i]+s[i+1:i-1:-1]+s[i+2:]
else: print s[1]+s[0]+s[2:]
Since you wish to actually compare two strings to see if they "are the same by swapping two characters around," you do not actually need to generate all possible combinations, instead you can iterate through each of the characters in each of the strings and ensure that no more than two of them are not equal.
This can be done as follows:
def twoCharactersDifferent(str1,str2):
if sorted(str1) != sorted(str2): #they must contain the same letters, exactly!
return False
numDifferent = 0
for i in range(len(str1)):
numDifferent += (str1[i] != str2[i])
if numDifferent >2:
return False
return True
print twoCharactersDifferent('wings','winxg')