Remove Single Char in String Python 2.7 - python

I have written the above program. The program supposed to do remove chr from str if str has chr in it and character follow chr is different than chr.
Can anyone here help me what's going on this? Why is not working as supposed? I see some problems with function calling inside a function.
def removesingleton(str,chr):
'''
(str,str)->(str)
Returns str with removed single chr
>>>removesingleton("Welcomee","e")
Wlcomee
>>>removesingleton("XabXXaX","X")
abXXa
'''
output, index = "", 0
if str:
for char in str:
if char == chr:
if index+1 < len(str) and str[index+1] == chr:
output += str[:index+2]
removesingleton(str[index+2:],chr)
else:
removesingleton(str[index+1:],chr)
else:
output += str[index]
removesingleton(str[index+1:],chr)
index += 1
return output
print removesingleton("XabXXaX","X")

You don't need any of the recursive calls. They're completely unnecessary, since you're doing a loop over the whole string within the single call. (You were also ignoring the return value, so there was not much point in recursing in the first place.)
What you do need is to check both the next character and the previous one to see if the current character is part of a repeated sequence. You don't need to do any slicing, nor do you even need an explicit loop. Here's a working version of the code, distilled down to a single generator expression inside a str.join call:
def removesingleton(s, ch):
'''
(str,str)->(str)
Returns a copy of s with all non-repeated instances of ch removed
>>>removesingleton("Welcomee","e")
Wlcomee
>>>removesingleton("XabXXaX","X")
abXXa
'''
return "".join(c for i, c in enumerate(s) # enumerate gives us our index
if c != ch or # keep any of: non-matching characters
(i > 0 and s[i-1] == ch) or # previous character was the same
(i < len(s)-1 and s[i+1] == ch)) # next character is the same

Related

how to recursively create nested list from string input

So, I would like to convert my string input
'f(g,h(a,b),a,b(g,h))'
into the following list
['f',['g','h',['a','b'],'a','b',['g','h']]]
Essentially, I would like to replace all '(' into [ and all ')' into ].
I have unsuccessfully tried to do this recursively. I thought I would iterate through all the variables through my word and then when I hit a '(' I would create a new list and start extending the values into that newest list. If I hit a ')', I would stop extending the values into the newest list and append the newest list to the closest outer list. But I am very new to recursion, so I am struggling to think of how to do it
word='f(a,f(a))'
empty=[]
def newlist(word):
listy=[]
for i, letter in enumerate(word):
if letter=='(':
return newlist([word[i+1:]])
if letter==')':
listy.append(newlist)
else:
listy.extend(letter)
return empty.append(listy)
Assuming your input is something like this:
a = 'f,(g,h,(a,b),a,b,(g,h))'
We start by splitting it into primitive parts ("tokens"). Since your tokens are always a single symbol, this is rather easy:
tokens = list(a)
Now we need two functions to work with the list of tokens: next_token tells us which token we're about to process and pop_token marks a token as processed and removes it from the list:
def next_token():
return tokens[0] if tokens else None
def pop_token():
tokens.pop(0)
Your input consist of "items", separated by a comma. Schematically, it can be expressed as
items = item ( ',' item )*
In the python code, we first read one item and then keep reading further items while the next token is a comma:
def items():
result = [item()]
while next_token() == ',':
pop_token()
result.append(item())
return result
An "item" is either a sublist in parentheses or a letter:
def item():
return sublist() or letter()
To read a sublist, we check if the token is a '(', the use items above the read the content and finally check for the ')' and panic if it is not there:
def sublist():
if next_token() == '(':
pop_token()
result = items()
if next_token() == ')':
pop_token()
return result
raise SyntaxError()
letter simply returns the next token. You might want to add some checks here to make sure it's indeed a letter:
def letter():
result = next_token()
pop_token()
return result
You can organize the above code like this: have one function parse that accepts a string and returns a list and put all functions above inside this function:
def parse(input_string):
def items():
...
def sublist():
...
...etc
tokens = list(input_string)
return items()
Quite an interesting question, and one I originally misinterpreted. But now this solution works accordingly. Note that I have used list concatenation + operator for this solution (which you usually want to avoid) so feel free to improve upon it however you see fit.
Good luck, and I hope this helps!
# set some global values, I prefer to keep it
# as a set incase you need to add functionality
# eg if you also want {{a},b} or [ab<c>ed] to work
OPEN_PARENTHESIS = set(["("])
CLOSE_PARENTHESIS = set([")"])
SPACER = set([","])
def recursive_solution(input_str, index):
# base case A: when index exceeds or equals len(input_str)
if index >= len(input_str):
return [], index
char = input_str[index]
# base case B: when we reach a closed parenthesis stop this level of recursive depth
if char in CLOSE_PARENTHESIS:
return [], index
# do the next recursion, return it's value and the index it stops at
recur_val, recur_stop_i = recursive_solution(input_str, index + 1)
# with an open parenthesis, we want to continue the recursion after it's associated
# closed parenthesis. and also the recur_val should be within a new dimension of the list
if char in OPEN_PARENTHESIS:
continued_recur_val, continued_recur_stop_i = recursive_solution(input_str, recur_stop_i + 1)
return [recur_val] + continued_recur_val, continued_recur_stop_i
# for spacers eg "," we just ignore it
if char in SPACER:
return recur_val, recur_stop_i
# and finally with normal characters, we just extent it
return [char] + recur_val, recur_stop_i
You can get the expected answer using the following code but it's still in string format and not a list.
import re
a='(f(g,h(a,b),a,b(g,h))'
ans=[]
sub=''
def rec(i,sub):
if i>=len(a):
return sub
if a[i]=='(':
if i==0:
sub=rec(i+1,sub+'[')
else:
sub=rec(i+1,sub+',[')
elif a[i]==')':
sub=rec(i+1,sub+']')
else:
sub=rec(i+1,sub+a[i])
return sub
b=rec(0,'')
print(b)
b=re.sub(r"([a-z]+)", r"'\1'", b)
print(b,type(b))
Output
[f,[g,h,[a,b],a,b,[g,h]]
['f',['g','h',['a','b'],'a','b',['g','h']] <class 'str'>

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))

Find last occurrence of character in string without built-in function

I need to make a function in Python 2.7 that does not use any built-in functions to find the last occurrence of a character in a string. It should work like:
string="This is a string with plenty of eeeeees"
string.rfind("e")
But the .rfind has to be replaced with a function created in the code like:
def lastocc(string, char):
# Function code
The below code will iterate over your string, and if it finds the matching character updates the found_at variable with the index of it in the string. It also uses the common idiom of returning -1 if the character is not present in the string.
def last_occurence(s, char):
found_at = -1
index = 0
for s_char in s:
if s_char == char:
found_at = index
index += 1
return found_at
If you could use the len() built-in, you could start your iteration from the end of the string, and take the length-negative_index to find it instead.
I hope that there is not too much built-in functions:
def lastocc(string, char):
m=-1;
i=0;
while i>=0:
try:
if string[i]==char:
m=i;
i+=1
except Exception:
i=-1;
return(m);
print(lastocc("1234561234", "0"))
def lastocc(somestr, char):
return max(i for i,c in enumerate(somestr) if c==char)
Or if you don't want to use any builtins whatsoever, you could do this:
def lastocc(somestr, char):
if not somestr: return -1
if somestr[-1] == char: return len(somestr)-1
return lastocc(somestr[:-1], char)

'NoneType' object is not iterable - looping w/returned value

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.

Categories