Getting the middle character in a odd length string - python

def get_middle_character(odd_string):
variable = len(odd_string)
x = str((variable/2))
middle_character = odd_string.find(x)
middle_character2 = odd_string[middle_character]
return middle_character2
def main():
print('Enter a odd length string: ')
odd_string = input()
print('The middle character is', get_middle_character(odd_string))
main()
I need to figure out how to print the middle character in a given odd length string. But when I run this code, I only get the last character. What is the problem?

You need to think more carefully about what your code is actually doing. Let's do this with an example:
def get_middle_character(odd_string):
Let's say that we call get_middle_character('hello'), so odd_string is 'hello':
variable = len(odd_string) # variable = 5
Everything is OK so far.
x = str((variable/2)) # x = '2'
This is the first thing that is obviously odd - why do you want the string '2'? That's the index of the middle character, don't you just want an integer? Also you only need one pair of parentheses there, the other set is redundant.
middle_character = odd_string.find(x) # middle_character = -1
Obviously you can't str.find the substring '2' in odd_string, because it was never there. str.find returns -1 if it cannot find the substring; you should use str.index instead, which gives you a nice clear ValueError when it can't find the substring.
Note that even if you were searching for the middle character, rather than the stringified index of the middle character, you would get into trouble as str.find gives the first index at which the substring appears, which may not be the one you're after (consider 'lolly'.find('l')...).
middle_character2 = odd_string[middle_character] # middle_character2 = 'o'
As Python allows negative indexing from the end of a sequence, -1 is the index of the last character.
return middle_character2 # return 'o'
You could actually have simplified to return odd_string[middle_character], and removed the superfluous assignment; you'd have still had the wrong answer, but from neater code (and without middle_character2, which is a terrible name).
Hopefully you can now see where you went wrong, and it's trivially obvious what you should do to fix it. Next time use e.g. Python Tutor to debug your code before asking a question here.

You need to simply access character based on index of string and string slicing. For example:
>>> s = '1234567'
>>> middle_index = len(s)/2
>>> first_half, middle, second_half = s[:middle_index], s[middle_index], s[middle_index+1:]
>>> first_half, middle, second_half
('123', '4', '567')
Explanation:
str[:n]: returns string from 0th index to n-1th index
str[n]: returns value at nth index
str[n:]: returns value from nth index till end of list

Should be like below:
def get_middle_character(odd_string):
variable = len(odd_string)/2
middle_character = odd_string[variable +1]
return middle_character

i know its too late but i post my solution
I hope it will be useful ;)
def get_middle_char(string):
if len(string) % 2 == 0:
return None
elif len(string) <= 1:
return None
str_len = int(len(string)/2))
return string[strlen]

reversedString = ''
print('What is your name')
str = input()
idx = len(str)
print(idx)
str_to_iterate = str
for char in str_to_iterate[::-1]:
print(char)
evenodd = len(str) % 2
if evenodd == 0:
print('even')
else:
print('odd')
l = str
if len(l) % 2 == 0:
x = len(l) // 2
y = len(l) // 2 - 1
print(l[x], l[y])
else:
n = len(l) // 2
print(l[n])

Related

First Unique Character

Given a string, find the first non-repeating character in it and return its index. If it doesn't exist, return -1. Input string already all lowercase.
Why does my code not work?
str1 = input("give me a string: ")
def unique(x):
stack = []
if x is None:
return (-1)
i = 0
while i < len(x):
stack = stack.append(x[i])
if x[i] in stack:
return(i)
else:
i += 1
unique(str1)
str1 = input("give me a string: ")
def unique(x):
for i in x:
if x.count(i) == 1:
return x.index(i)
else:
return -1
print(unique(str1))
This will work
Explanation
Instead of using the list stack use the count() function of the string. The function unique(x) will return the index of that first element whose count is 1 in the str1 string.
You need to know what your code is doing to figure out why it doesn't work, let's breakthrough it step by step.
you create a empty list stack for later use, that's fine.
if x is None is a strange way to check if a string is given, and it doesn't work because even a empty string "" is not equal to None. is is used to check if both sides are the same object, and == is a better operator to check if values of both sides are the same. Therefore, if x == "" is better, but if not x is even better to check if something is empty.
using variable i and while loop to iterate the string is fine.
append() change the list in-place and return None, so stack = stack.append(x[i]) is assigning None to stack.
in stack is going to raise TypeError as NoneType is not iterable. If we change the last line to stack.append(x[i]), it now works, as x[0] is already appended to stack, if x[0] in stack must be True and return 0 for your result.
That's what your code is doing, you just append the first character and return the first index. You need to go through the whole string to know if a character is unique.
Although Rishabh's answer is cleaner, I provide a way to doing it using lists to save seen and repeated characters, then read the string again to find the index of unique character.
x = input("give me a string: ")
def unique(x):
seen = []
repeated = []
for char in x:
if char in seen:
repeated.append(char)
else:
seen.append(char)
for idx, char in enumerate(x):
if char not in repeated:
return idx
return -1
print(unique(x))

Recursive function to obtain non-repeated characters from string

I have this exercise:
Write a recursive function that takes a string and returns all the characters that are not repeated in said string.
The characters in the output don't need to have the same order as in the input string.
First I tried this, but given the condition for the function to stop, it never evaluates the last character:
i=0
lst = []
def list_of_letters_rec(str=""):
if str[i] not in lst and i < len(str) - 1:
lst.append(str[i])
list_of_letters_rec(str[i+1:])
elif str[i] in lst and i < len(str) - 1:
list_of_letters_rec(str[i+1:])
elif i > len(str) - 1:
return lst
return lst
word = input(str("Word?"))
print(list_of_letters_rec(word))
The main issue with this function is that it never evaluates the last character.
An example of an output:
['a', 'r', 'd', 'v'] for input 'aardvark'.
Since the characters don't need to be ordered, I suppose a better approach would be to do the recursion backwards, and I also tried another approach (below), but no luck:
lst = []
def list_of_letters_rec(str=""):
n = len(str) - 1
if str[n] not in lst and n >= 0:
lst.append(str[n])
list_of_letters_rec(str[:n-1])
elif str[n] in lst and n >= 0:
list_of_letters_rec(str[:n-1])
return lst
word = input(str("Word?"))
print(list_of_letters_rec(word))
Apparently, the stop conditions are not well defined, especially in the last one, as the output I get is
IndexError: string index out of range
Could you give me any hints to help me correct the stop condition, either in the 1st or 2nd try?
You can try:
word = input("> ")
result = [l for l in word if word.count(l) < 2]
> aabc
['b', 'c']
Demo
One improvement I would offer on #trincot's answer is the use of a set, which has better look-up time, O(1), compared to lists, O(n).
if the input string, s, is empty, return the empty result
(inductive) s has at least one character. if the first character, s[0] is in the memo, mem, the character has already been seen. Return the result of the sub-problem, s[1:]
(inductive) The first character is not in the memo. Add the first character to the memo and prepend the first character to the result of the sub-problem, s[1:]
def list_of_letters(s, mem = set()):
if not s:
return "" #1
elif s[0] in mem:
return list_of_letters(s[1:], mem) #2
else:
return s[0] + list_of_letters(s[1:], {*mem, s[0]}) #3
print(list_of_letters("aardvark"))
ardvk
Per your comment, the exercise asks only for a string as input. We can easily modify our program to privatize mem -
def list_of_letters(s): # public api
def loop(s, mem): # private api
if not s:
return ""
elif s[0] in mem:
return loop(s[1:], mem)
else:
return s[0] + loop(s[1:], {*mem, s[0]})
return loop(s, set()) # run private func
print(list_of_letters("aardvark")) # mem is invisible to caller
ardvk
Python's native set data type accepts an iterable which solves this problem instantly. However this doesn't teach you anything about recursion :D
print("".join(set("aardvark")))
akdrv
Some issues:
You miss the last character because of i < len(str) - 1 in the conditionals. That should be i < len(str) (but read the next points, as this still needs change)
The test for if i > len(str) - 1 should come first, before doing anything else, otherwise you'll get an invalid index reference. This also makes the other conditions on the length unnecessary.
Don't name your variable str, as that is already a used name for the string type.
Don't populate a list that is global. By doing this, you can only call the function once reliably. Any next time the list will still have the result of the previous call, and you'll be adding to that. Instead use the list that you get from the recursive call. In the base case, return an empty list.
The global i has no use, since you never change its value; it is always 0. So you should just reference index [0] and check that the string is not empty.
Here is your code with those corrections:
def list_of_letters_rec(s=""):
if not s:
return []
result = list_of_letters_rec(s[1:])
if s[0] not in result:
result.append(s[0])
return result
print(list_of_letters_rec("aardvark"))
NB: This is not the most optimal way to do it. But I guess this is what you are asked to do.
A possible solution would be to just use an index instead of splicing the string:
def list_of_letters_rec(string="", index = 0, lst = []):
if(len(string) == index):
return lst
char = string[index]
if string.count(char) == 1:
lst.append(char)
return list_of_letters_rec(string, index+1, lst)
word = input(str("Word?"))
print(list_of_letters_rec(word))

Determining validity if sum divisible by 10

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'm trying to replace a character in Python while iterating over a string and but it doesn't work

This is the code I currently have:
letter = raw_input("Replace letter?")
traversed = raw_input("Traverse in?")
replacewith = raw_input("Replace with?")
traverseint = 0
for i in traversed:
traverseint = traverseint + 1
if i == letter:
traversed[traverseint] = replacewith
print i
print(traversed)
str in python are immutable by nature. That means, you can not modify the existing object. For example:
>>> 'HEllo'[3] = 'o'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
In order to replace the character in the string, ideal way is to use str.replace() method. For example:
>>> 'HEllo'.replace('l', 'o')
'HEooo'
Without using str.replace(), you may make your program run by using a temporary string as:
my_str = '' # Temporary string
for i in traversed:
# traverseint = traverseint + 1 # Not required
if i == letter:
i = replacewith
my_str += i
Here my_str will hold the value of transformed traversed. OR, even better way to do this is by transforming the string to list (as mentioned by #chepner), update the values of list and finally join the list to get back the string. For example:
traversed_list = list(traversed)
for i, val in enumerate(traversed_list):
if val == letter:
traversed_list[i] = replacewith
print i
my_str = ''.join(traversed_list)
I can not comment yet, but want add a bit to Moinuddin Quadri answer.
If index of replacement is not required, str.replace() should be a best solution.
If replacement index is required, just use str.index() or str.find() for determine an replacement index, then use slice (see table) to "cut" ends and sum replacement between begin and end, or just call str.replace().
while True:
index = traversed.find(letter)
if index < 0:
break
print index
traversed = traversed[:index] + replacewith + traversed[index + len(letter):]
#or
traversed = traversed.replace(letter, replacewith, 1)
Str is immutable, so direct slice assignment is not possible.
If you want directly modify a string, you should use a mutable type, like bytearray.
To check if string contains a substring you can use in
letter in traversed
"System" does not allow me to post more than 2 links. But all methods I have mentioned are on the same page.
You shouldn't modify containers you are iterating over. And you cant edit strings by position.
Make a copy of the string first and make it a list object
letter = raw_input("Replace letter?")
traversed = raw_input("Traverse in?")
modify = list(traversed)
replacewith = raw_input("Replace with?")
for traverseint,i in enumerate(modify):
if i == letter:
modify[traverseint] = replacewith
print i
print(''.join(modify))
You can also just create empty string and add letters (python 3.5)
letter = input("Replace letter?")
traversed = input("Traverse in?")
replacewith = input("Replace with?")
temp = ''
for i in traversed:
if i == letter:
temp += replacewith
else:
temp += i
print(temp)
We can also define own replace like below:
def replace(str, idx, char):
if -1 < idx < len(str):
return '{str_before_idx}{char}{str_after_idx}'.format(
str_before_idx=str[0:idx],
char=char,
str_after_idx=str[idx+1:len(str)]
)
else:
raise IndexError
Where str is string to be manipulated, idx is an index, char is character to be replaced at index idx.

implement rfind in Python

I am attempting to implement the rfind function in Python without using the built-in rfind method. It should work like the following:
Unlike the original method, takes an input string and a character as a parameter and returns the first index from the right where the character is found. Now I am getting stuck on what to do next..
# main function
inputString = input("Enter here: ")
inputChar = input("Which character would you like to find?")
print(Myrfind(inputString, inputChar))
def Myrfind(text,aChar):
reverseString = text[::-1]
for ch in reverseString:
if ch == aChar:
print()
else:
return -1
The simplest approach, IMHO, would be to just iterate over the string backwards and compare each character:
def myrfind(text, aChar):
for i in range(len(text) - 1, -1, -1):
if text[i] == aChar:
return i
return -1
Your function should be like (with minimal changes in current code):
def Myrfind(text,aChar):
reverseString = text[::-1]
for i, c in enumerate(reverseString): # enumerate() to iterate along with index
if c == aChar:
return len(text) - i - 1 # Return len(char) - i -1 since reverse string
else: # Return -1 if function is not
return -1 # exited by for loop
Sample run:
>>> Myrfind('Hello', 'o')
4
>>> Myrfind('Hello', 'l')
3
>>> Myrfind('Hello', 'e')
1
>>> Myrfind('Hello', 'a') # 'a' not in string
-1
So, in ch you have the character, not the index of the character, so even if you find it, you won't be able to know its index (you just know that the character is in your text string, nothing else)
Also, when you find a coincidence, you print... nothing (in print())
And since the return -1 (when not found) is within the for loop, you will stop the execution (returning -1) as soon as a character doesn't match the looked up character (you should be very familiar with the return statement)
You reverse the string, but that is probably not very... "adviseable", because then your indexes get reversed. For instance, let's say you want to find the last l in Hello. You are expecting:
H e l l o
Index 0 1 2 3 4
And that should be 3, but since you reverse it, and start walking it from left to right, you get:
o l l e H
Index 0 1 2 3 4
And the first match is in 1, now... You can still do it, though... You can substract that index to the total lenght, and you should get it.
Firstly, I would recommend you read what the enumerate built-in does (to not only get the character, but also the index)
A pretty close thing to what you have could be:
inputString = input("Enter here: ")
inputChar = input("Which character would you like to find?")
def Myrfind(text,aChar):
reverseString = text[::-1]
for i, ch in enumerate(reverseString):
if ch == aChar:
return len(text) - 1 - i
return -1
print(Myrfind(inputString, inputChar))
Or, instead of inverting the array, just start reading from the right (see what range does)
def Myrfind(text,aChar):
for i in range(len(text) - 1, -1, -1):
ch = text[i]
if ch == aChar:
return i
return -1

Categories