Removing an element from python string recursively? - python

I'm trying to figure out how to write a program that would remove a given element from a python string recursively. Here's what I have so far:
def remove(x,s):
if x == s[0]:
return ''
else:
return s[0] + remove(x,s[1:])
When testing this code on the input remove('t', 'wait a minute'), it seems to work up until it reaches the first 't', but the code then terminates instead of continuing to go through the string. Does anyone have any ideas of how to fix this?

In your code, you return '' when you run into the character you're removing.
This will drop the rest of the string.
You want to keep going through the string instead (also pass x in recursive calls and add a base case):
def remove(x, s):
if not s:
return ''
if x == s[0]:
return remove(x, s[1:])
else:
return s[0] + remove(x, s[1:])
Also, in case you didn't know, you can use str.replace() to achieve this:
>>> 'wait a minute'.replace('t', '')
'wai a minue'

def Remove(s,e):
return filter(lambda x: x!= e, s)
Here is an example for your test
sequence = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
RemoveElement = ['d','c']
print(filter(lambda x: x not in RemoveElement, sequence))
#['a', 'b', 'e', 'f', 'g', 'h']

if you are just replacing/removing a character like 't' you could just use a list comprehension:
s = 'wait a minute'
xs = ''.join(x for x in s if x != 't')

Related

python - how to use the join method and sort method

My purpose is to get an input as a string and return a list of lower case letters of that string, without repeats, without punctuations, in alphabetical order. For example, the input "happy!" would get ['a','h','p','y']. I try to use the join function to get rid of my punctuations but somehow it doesn't work. Does anybody know why? Also, can sort.() sort alphabets? Am I using it in the right way? Thanks!
def split(a):
a.lower()
return [char for char in a]
def f(a):
i=split(a)
s=set(i)
l=list(s)
v=l.join(u for u in l if u not in ("?", ".", ";", ":", "!"))
v.sort()
return v
.join() is a string method, but being used on a list, so the code raises an exception, but join and isn't really needed here.
You're on the right track with set(). It only stores unique items, so create a set of your input and compute the intersection(&) with lower case letters. Sort the result:
>>> import string
>>> s = 'Happy!'
>>> sorted(set(s.lower()) & set(string.ascii_lowercase))
['a', 'h', 'p', 'y']
You could use:
def f(a):
return sorted(set(a.lower().strip('?.;:!')))
>>> f('Happy!')
['a', 'h', 'p', 'y']
You could also use regex for this:
pattern = re.compile(r'[^a-z]')
string = 'Hello# W0rld!!##'
print(sorted(set(pattern.sub('', string))))
Output:
['d', 'e', 'l', 'o', 'r']

'Clumping' a list in python

I've been trying to 'clump' a list
I mean putting items together depending on the item inbetween, so ['d','-','g','p','q','-','a','v','i'] becomes ['d-g','p','q-a','v','i'] when 'clumped' around any '-'
Here's my attempt:
def clump(List):
box = []
for item in List:
try:
if List[List.index(item) + 1] == "-":
box.append("".join(List[List.index(item):List.index(item)+3]))
else:
box.append(item)
except:
pass
return box
However, it outputs (for the example above)
['d-g', '-', 'g', 'p', 'q-a', '-', 'a', 'v']
As I have no idea how to skip the next two items
Also, the code is a complete mess, mainly due to the try and except statement (I use it, otherwise I get an IndexError, when it reaches the last item)
How can it be fixed (or completely rewritten)?
Thanks
Here's an O(n) solution that maintains a flag determining whether or not you are currently clumping. It then manipulates the last item in the list based on this condition:
def clump(arr):
started = False
out = []
for item in arr:
if item == '-':
started = True
out[-1] += item
elif started:
out[-1] += item
started = False
else:
out.append(item)
return out
In action:
In [53]: clump(x)
Out[53]: ['d-g', 'p', 'q-a', 'v', 'i']
This solution will fail if the first item in the list is a dash, but that seems like it should be an invalid input.
Here is a solution using re.sub
>>> import re
>>> l = ['d','-','g','p','q','-','a','v','i']
>>> re.sub(':-:', '-', ':'.join(l)).split(':')
['d-g', 'p', 'q-a', 'v', 'i']
And here is another solution using itertools.zip_longest
>>> from itertools import zip_longest
>>> l = ['d','-','g','p','q','-','a','v','i']
>>> [x+y+z if y=='-' else x for x,y,z in zip_longest(l, l[1:], l[2:], fillvalue='') if '-' not in [x,z]]
['d-g', 'g', 'q-a', 'a', 'v', 'i']

Python permutation using backtracking

I'm just trying to learn permutation using backtracking. I've written the following code but it stops after first output.
def permutations(str_in, soFar):
if len(str_in) != 0:
for c in str_in:
soFar.append(c)
temp_str = str_in
temp_str.remove(c)
print temp_str, soFar
permutations(temp_str, soFar)
else:
print soFar
inp = "ABCD"
str_in = list(inp)
permutations(str_in, [])
This is the output I'm getting for this:
['B', 'C', 'D'] ['A']
['C', 'D'] ['A', 'B']
['D'] ['A', 'B', 'C']
[] ['A', 'B', 'C', 'D']
['A', 'B', 'C', 'D']
I'm sure this is something simple, but I'm not able to understand what mistake I'm making here.
Here is Geeksforgeeks method, by Bhavya Jain, of permuting a string. The missing logic in your code is the recursive step on the sublists and a swapping behavior. Here is their visualization.
def permute(a, l, r):
if l==r:
print toString(a)
else:
for i in xrange(l,r+1):
a[l], a[i] = a[i], a[l]
permute(a, l+1, r)
a[l], a[i] = a[i], a[l] # backtrack
# Driver program to test the above function
string = "ABC"
n = len(string)
a = list(string)
permute(a, 0, n-1)
Output
['A', 'B', 'C']
['A', 'C', 'B']
['B', 'A', 'C']
['B', 'C', 'A']
['C', 'B', 'A']
['C', 'A', 'B']
I rewrote it again and with some print commands in between I was able to reach the desired output. But still not entirely sure of the way it's working. I think it's mainly how python modifies a list with each call to the function. I had to assign temporary lists twice to make sure when tracing back the original lists are not modified. Anyway the following code is working.
def permute(String, SoFar):
TempString = list(String)
TempSoFar = list(SoFar)
#print TempString, TempSoFar
if TempString != []:
for c in String:
TStr = list(TempString)
TSF = list(TempSoFar)
TStr.remove(c)
TSF.append(c)
#print String, TStr, TSF
permute(TStr, TSF)
else:
print "\nOut: ", TempSoFar, "\n"
permute(list("ABCD"),list(""))
Second solution using strings rather than lists, as mentioned in my comment below.
def permute(String, SoFar):
#print "New Func Call: ", "SoFar: ", SoFar,"String: ", String, "\n"
if String != "":
for c in String:
TS = String.replace(c,"")
TSF = SoFar+c
permute(TS, TSF)
#print "A Call Finished", "SoFar: ", SoFar,"String: ", String, "TSF: ", TSF, "TS: ", TS
else:
print SoFar
permute("ABC","")

What is the python equivalent to perl "a".."azc"

In perl, to get a list of all strings from "a" to "azc", to only thing to do is using the range operator:
perl -le 'print "a".."azc"'
What I want is a list of strings:
["a", "b", ..., "z", "aa", ..., "az" ,"ba", ..., "azc"]
I suppose I can use ord and chr, looping over and over, this is simple to get for "a" to "z", eg:
>>> [chr(c) for c in range(ord("a"), ord("z") + 1)]
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
But a bit more complex for my case, here.
Thanks for any help !
Generator version:
from string import ascii_lowercase
from itertools import product
def letterrange(last):
for k in range(len(last)):
for x in product(ascii_lowercase, repeat=k+1):
result = ''.join(x)
yield result
if result == last:
return
EDIT: #ihightower asks in the comments:
I have no idea what I should do if I want to print from 'b' to 'azc'.
So you want to start with something other than 'a'. Just discard anything before the start value:
def letterrange(first, last):
for k in range(len(last)):
for x in product(ascii_lowercase, repeat=k+1):
result = ''.join(x)
if first:
if first != result:
continue
else:
first = None
yield result
if result == last:
return
A suggestion purely based on iterators:
import string
import itertools
def string_range(letters=string.ascii_lowercase, start="a", end="z"):
return itertools.takewhile(end.__ne__, itertools.dropwhile(start.__ne__, (x for i in itertools.count(1) for x in itertools.imap("".join, itertools.product(letters, repeat=i)))))
print list(string_range(end="azc"))
Use the product call in itertools, and ascii_letters from string.
from string import ascii_letters
from itertools import product
if __name__ == '__main__':
values = []
for i in xrange(1, 4):
values += [''.join(x) for x in product(ascii_letters[:26], repeat=i)]
print values
Here's a better way to do it, though you need a conversion function:
for i in xrange(int('a', 36), int('azd', 36)):
if base36encode(i).isalpha():
print base36encode(i, lower=True)
And here's your function (thank you Wikipedia):
def base36encode(number, alphabet='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', lower=False):
'''
Convert positive integer to a base36 string.
'''
if lower:
alphabet = alphabet.lower()
if not isinstance(number, (int, long)):
raise TypeError('number must be an integer')
if number < 0:
raise ValueError('number must be positive')
# Special case for small numbers
if number < 36:
return alphabet[number]
base36 = ''
while number != 0:
number, i = divmod(number, 36)
base36 = alphabet[i] + base36
return base36
I tacked on the lowercase conversion option, just in case you wanted that.
I generalized the accepted answer to be able to start middle and to use other than lowercase:
from string import ascii_lowercase, ascii_uppercase
from itertools import product
def letter_range(first, last, letters=ascii_lowercase):
for k in range(len(first), len(last)):
for x in product(letters, repeat=k+1):
result = ''.join(x)
if len(x) != len(first) or result >= first:
yield result
if result == last:
return
print list(letter_range('a', 'zzz'))
print list(letter_range('BA', 'DZA', ascii_uppercase))
def strrange(end):
values = []
for i in range(1, len(end) + 1):
values += [''.join(x) for x in product(ascii_lowercase, repeat=i)]
return values[:values.index(end) + 1]

How could I print out the nth letter of the alphabet in Python?

ASCII math doesn't seem to work in Python:
'a' + 5
DOESN'T WORK
How could I quickly print out the nth letter of the alphabet without having an array of letters?
My naive solution is this:
letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
print letters[5]
chr and ord convert characters from and to integers, respectively. So:
chr(ord('a') + 5)
is the letter 'f'.
ASCII math aside, you don't have to type your letters table by hand.
The string constants in the string module provide what you were looking for.
>>> import string
>>> string.ascii_uppercase[5]
'F'
>>>
chr(ord('a')+5)
​​​​​​​​​​​​​​​​​​​
if u want to go really out of the way (probably not very good) you could create a new class CharMath:
class CharMath:
def __init__(self,char):
if len(char) > 1: raise IndexError("Not a single character provided")
else: self.char = char
def __add__(self,num):
if type(num) == int or type(num) == float: return chr(ord(self.char) + num)
raise TypeError("Number not provided")
The above can be used:
>>> CharMath("a") + 5
'f'
import string
print string.letters[n + is_upper*26]
For example:
>>> n = 5
>>> is_upper = False
>>> string.letters[n+is_upper*26]
'f'
>>> is_upper = True
>>> string.letters[n+is_upper*26]
'F'
You need to use the ord function, like
print(ord('a')-5)
Edit: gah, I was too slow :)
If you like it short, try the lambda notation:
>>> A = lambda c: chr(ord('a')+c)
>>> A(5)
'f'

Categories

Resources