To make a recursive function with challenging constraints - python

I would like to make a function with an input string (for example 'abcdef'), and returns it in reverse order 'fedcba'.
However, the challenge is that the function
must use a recursive function
is without using for-loop
is without any operators
is without list slicing
This is my attempt which does not work:
def reverse(s: str) -> str
if len(s) == 0:
return None
return
How do I use the recursive function here to reverse order? I tried to think of it but i'm new to recursive calls

"without using for loops or any operators or list slicing" seems like a weird requirement, but the following function will do:
>>> def reverse(s):
... head, *tail = s
... if tail:
... return f'{reverse(tail)}{head}'
... else:
... return head
...
>>> reverse('abcdef')
'fedcba'
In the scope of lexical analysis, * is regarded as an operator, so we can replace head, *tail = s with the following:
import re
def reverse(s):
head, tail = re.split('(?!^)', s, maxsplit=1)
[...]
Or, alternatively:
def reverse(s):
__, head, tail = s.partition(next(iter(s))
[...]
Or, yet another alternative:
def reverse(s):
s = iter(s)
head, tail = next(s), ''.join(s)
[...]

Edit: I have removed the '+' operator, and also the lstrip() which does not work on repeated characters in the string (thanks #philosofool)
Here's one way to do it without list slicing. And to clarify s[0] is list indexing not list slicing, correct?
def reverse(s):
if len(s)==1:
return s
else:
s1 = list(s)
del s1[0]
return ''.join([reverse(''.join(s1)), s[0]])
reverse('abccdefg')
output is
'gfedccba'

This is not actually a solution. It meets all the requirements except the recursive one. It's a nice, purely functional solution, but not what OP asked for. Leaving it up in case anyone is interested....
from functools import reduce
def reverse_string(string):
return reduce(lambda x, y: f'{y}{x}', string)

Using only functions
def reverse(strng, pos):
if pos:
next_pos = map(lambda x: x, range(pos,0,-1))
next(next_pos) # skip first
return ''.join((strng[pos],reverse(strng, next(next_pos)))
else:
return strng[pos]
Another one inspired by #Ecin
def reverse(strng : str):
def inner(strng : list):
return ''.join((strng.pop(), inner(strng) if strng else ''))
return inner(list(strng))

Related

python build a list recursively

Let's say I have a string
S = "qwertyu"
And I want to build a list using recursion so the list looks like
L = [u, y, t, r, e, w, q]
I tried to write code like this:
def rec (S):
if len(S) > 0:
return [S[-1]].append(rec(S[0:-1]))
Ideally I want to append the last element of a shrinking string until it reaches 0
but all I got as an output is None
I know I'm not doing it right, and I have absolutely no idea what to return when the length of S reaches 0, please show me how I can make this work
(sorry the answer has to use recursion, otherwise it won't bother me)
Thank you very much!!!
There are many simpler ways than using recursion, but here's one recursive way to do it:
def rec (S):
if not S:
return []
else:
temp = list(S[-1])
temp.extend(rec(S[:-1]))
return temp
EDIT:
Notice that the base case ensures that function also works with an empty string. I had to use temp, because you cannot return list(S[-1]).extend(rec(S[:-1])) due to it being a NoneType (it's a method call rather than an object). For the same reason you cannot assign to a variable (hence the two separate lines with temp). A workaround would be to use + to concatenate the two lists, like suggested in Aryerez's answer (however, I'd suggest against his advice to try to impress people with convoluted one liners):
def rec (S):
if not S:
return []
else:
return list(S[-1]) + rec(S[:-1])
In fact using + could be more efficient (although the improvement would most likely be negligible), see answers to this SO question for more details.
This is the simplest solution:
def rec(S):
if len(S) == 1:
return S
return S[-1] + rec(S[:-1])
Or in one-line, if you really want to impress someone :)
def rec(S):
return S if len(S) == 1 else S[-1] + rec(S[:-1])
Since append mutates the list, this is a bit difficult to express recursively. One way you could do this is by using a separate inner function that passes on the current L to the next recursive call.
def rec(S):
def go(S, L):
if len(S) > 0:
L.append(S[-1])
return go(S[0:-1], L)
else:
return L
return go(S, [])
L = [i for i in S[::-1]]
It should work.

Python from tuples to strings

new to the python programming, havin some difficulties figuring this out.
I'm trying to convert tuples into strings, for example ('h','e',4) into 'he4'. i've submitted a version using the .join function, and i'm required to come up with another ver. i'm given the following:
def filter(pred, seq): # keeps elements that satisfy predicate
if seq == ():
return ()
elif pred(seq[0]):
return (seq[0],) + filter(pred, seq[1:])
else:
return filter(pred, seq[1:])
def accumulate(fn, initial, seq):
if seq == ():
return initial
else:
return fn(seq[0], accumulate(fn, initial, seq[1:]))
hints on how to use the following to come up with conversion of tuples to strings?
The given filter is useless for this but the given accumulate can be used easily:
>>> t = ('h','e',4)
>>> accumulate(lambda x, s: str(x) + s, '', t)
'he4'
Just loop through the tuple.
#tup stores your tuple
string = ''
for s in tuple :
string+=s
Here you are going through the tuple and adding each element of it into a new string.
1) Use reduce function:
>>> t = ('h','e',4)
>>> reduce(lambda x,y: str(x)+str(y), t, '')
'he4'
2) Use foolish recursion:
>>> def str_by_recursion(t,s=''):
if not t: return ''
return str(t[0]) + str_by_recursion(t[1:])
>>> str_by_recursion(t)
'he4'
You can use map to and join.
tup = ('h','e',4)
map_str = map(str, tup)
print(''.join(map_str))
Map takes two arguments. First argument is the function which has to be used for each element of the list. Second argument is the iterable.

Fast and pythonic way to find out if a string is a palindrome

[Edit: as someone pointed out I have used improperly the palindrom concept, now I have edited with the correct functions. I have done also some optimizations in the first and third example, in which the for statement goes until it reach half of the string]
I have coded three different versions for a method which checks if a string is a palindrome. The method are implemented as extensions for the class "str"
The methods also convert the string to lowercase, and delete all the punctual and spaces. Which one is the better (faster, pythonic)?
Here are the methods:
1) This one is the first solution that I thought of:
def palindrom(self):
lowerself = re.sub("[ ,.;:?!]", "", self.lower())
n = len(lowerself)
for i in range(n//2):
if lowerself[i] != lowerself[n-(i+1)]:
return False
return True
I think that this one is the more faster because there aren't transformations or reversing of the string, and the for statement breaks at the first different element, but I don't think it's an elegant and pythonic way to do so
2) In the second version I do a transformation with the solution founded here on stackoverflow (using advanced slicing string[::-1])
# more compact
def pythonicPalindrom(self):
lowerself = re.sub("[ ,.;:?!]", "", self.lower())
lowerReversed = lowerself[::-1]
if lowerself == lowerReversed:
return True
else:
return False
But I think that the slicing and the comparision between the strings make this solution slower.
3) The thirds solution that I thought of, use an iterator:
# with iterator
def iteratorPalindrom(self):
lowerself = re.sub("[ ,.;:?!]", "", self.lower())
iteratorReverse = reversed(lowerself)
for char in lowerself[0:len(lowerself)//2]:
if next(iteratorReverse) != char:
return False
return True
which I think is way more elegant of the first solution, and more efficient of the second solution
So, I decided to just timeit, and find which one was the fastest. Note that the final function is a cleaner version of your own pythonicPalindrome. It is defined as follows:
def palindrome(s, o):
return re.sub("[ ,.;:?!]", "", s.lower()) == re.sub("[ ,.;:?!]", "", o.lower())[::-1]
Methodology
I ran 10 distinct tests per function. In each test run, the function was called 10000 times, with arguments self="aabccccccbaa", other="aabccccccbaa". The results can be found below.
palindrom iteratorPalindrome pythonicPalindrome palindrome
1 0.131656638 0.108762937 0.071676536 0.072031984
2 0.140950052 0.109713793 0.073781851 0.071860462
3 0.126966087 0.109586756 0.072349792 0.073776719
4 0.125113136 0.108729573 0.094633969 0.071474645
5 0.130878159 0.108602964 0.075770395 0.072455015
6 0.133569472 0.110276694 0.072811747 0.071764222
7 0.128642812 0.111065438 0.072170571 0.072285204
8 0.124896702 0.110218949 0.071898959 0.071841214
9 0.123841905 0.109278358 0.077430437 0.071747112
10 0.124083576 0.108184210 0.080211147 0.077391086
AVG 0.129059854 0.109441967 0.076273540 0.072662766
STDDEV 0.005387429 0.000901370 0.007030835 0.001781309
It would appear that the cleaner version of your pythonicPalindrome is marginally faster, but both functions clearly outclass the alternatives.
It seems that you want to know the execution time of your blocks of code and compare them.
You can use the timeit module.
Here's a quick way:
import timeit
start = timeit.default_timer()
#Your code here
stop = timeit.default_timer()
print stop - start
Read more:
Option 1
Option 2
You could also time this one-liner that does not use re, but itertools instead:
def isPalindrom(self):
return all(i==j for i, j in itertools.zip_longest((i.lower() for i in self if i not in " ,.;:?!"), (j.lower() for j in self[::-1] if j not in " ,.;:?!")))
Or, explained in more details:
def isPalindrom(self):
#using generators to not use memory
stripped_self = (i.lower() for i in self if i not in " ,.;:?!")
reversed_stripped_self = (j.lower() for j in self[::-1] if j not in " ,.;:?!")
return all(self_char==reversed_char for self_char, reversed_char in itertools.zip_longest(stripped_self, reversed_stripped_self))
Recall that filter works on strings:
>>> st="One string, with punc. That also needs lowercase!"
>>> filter(lambda c: c not in " ,.;:?!", st.lower())
'onestringwithpuncthatalsoneedslowercase'
So your test can be a one liner that is obvious in function:
>>> str
'!esacrewol sdeen osla tahT .cnup htiw ,gnirts enO'
>>> filter(lambda c: c not in " ,.;:?!", st.lower())==filter(lambda c: c not in " ,.;:?!", str.lower()[::-1])
True
Or, if you are going to use a regex, just reverse the result with the idiomatic str[::-1]:
>>> "123"[::-1]
'321'
>>> re.sub(r'[ ,.;:?!]', '', st.lower())==re.sub(r'[ ,.;:?!]', '', str.lower())[::-1]
True
The fastest may be to use string.tranlate to delete the characters:
>>> import string
>>> string.translate(st, None, " ,.;:?!")
'OnestringwithpuncThatalsoneedslowercase'
>>> string.translate(st, None, " ,.;:?!")==string.translate(str, None, " ,.;:?!")[::-1]
True
When we pass a word it checks if it can be reversed,If it can be reversed it prints "This is a Palindrome". or "This is NOT a Palindrome"
def reverse(word):
x = ''
for i in range(len(word)):
x += word[len(word)-1-i]
return x
word = input('give me a word:\n')
x = reverse(word)
if x == word:
print('This is a Palindrome')
else:
print('This is NOT a Palindrome')
Why not using a more pythonic way!
def palindrome_checker(string):
string = string.lower()
return string == string[::-1] # returns a boolean

Is it possible to sort in python 3 using buffer-like (pointer-based) string comparisons?

Consider the problem of sorting all the suffixes of a string, where a suffix is the substring from some index i to the end of the string. Instead of creating a list of the sorted suffixes, we can create a list of the indices corresponding to the starting points of the sorted suffixes. Then we can do something like this:
text = ... some text string ...
sortedIndices = sorted([i for i in range(len(text))],
key = lambda i: text[i:])
This works for short strings, but if the string is sufficiently long, we'll run out of memory because the key function results in a copy of the suffix, and all the keys are generated at the outset. In python 2.7 there's a slick way around this, namely, the buffer() function:
sortedIndices = sorted([i for i in range(len(text))],
key = lambda i: buffer(text, i))
In this case, the key is just a pointer into the text string, so the total memory needed is much less (O(n) vs O(n*n)). Hence, it will work with much longer strings. This works beautifully in 2.7, but in 3.x the buffer() function has been removed in favor of memoryview, which unlike buffer doesn't -- AFAIK -- support pointer-based string comparisons (i.e., without using the tobytes method, which creates a copy of the string). My question is: Is there any way to do something similar in python 3.x?
It looks to me like memoryview doesn't do that. That might actually be a good thing.
You can still do this with a class, which is more object oriented anyway:
#!/usr/local/cpython-3.3/bin/python
import sys
import functools
#functools.total_ordering
class Suffix_comparison:
def __init__(self, string, starting_position):
self.string = string
self.starting_position = starting_position
def __lt__(self, other):
if self.string[self.starting_position:] < other.string[other.starting_position]:
return True
else:
return False
def __eq__(self, other):
if self.string[self.starting_position:] == other.string[other.starting_position]:
return True
else:
return False
def __str__(self):
return self.string
__repr__ = __str__
def main():
list_ = []
for line in sys.stdin:
stripped_line = line.rstrip('\n')
list_.append(Suffix_comparison(stripped_line, 5))
list_.sort()
for line in list_:
print(line)
main()
Well I've been working on this problem too.
And I've just shifted from Python 2.7 to 3. WinPython, which has a very cool editor called Spyder by the way.
As far as I can tell, memoryview objects are totally useless.
I also tried the itertools.islice function, but couldn't see how to get that going either.
So decided to write my own little comparison function:
def suffixArrayCompare(x, y):
global globalText
i = 0
end = len(globalText) - max(x, y)
while i < end:
if globalText[x+i] < globalText[y+i]:
return -1
elif globalText[x+i] > globalText[y+i]:
return 1
i += 1
return 0
And it's called like this:
indexes = sorted(indexes, key = functools.cmp_to_key(lambda x,y:suffixArrayCompare(x, y)))
This is as fast as I can make this run. It's still not as fast as the buffer way in 2.7, but not too far off. And it doesn't copy anything.
This
#indexes = sorted(indexes, key = lambda x: globalText[x:])
runs nearly as fast, but has the memory problems you mention.

List membership in Python without "in"

How to define a function is_member() that takes a value (i.e. a number, string, etc) x and a list of values a, and returns True if x is a member of a, False otherwise. (Note that this is exactly what the in operator does, but for the sake of the exercise I should pretend Python did not have this operator.
This is what I've come up with, but it doesn't work!
def is_member(x, a):
return x == a[::]
I can think of two (edit: three) ways to do this:
First:
def is_member(array, value):
try:
array.index(value)
except ValueError:
return False
else:
return True
Second:
def is_member(array, value):
for item in array:
if item == value:
return True
return False
EDIT: Also, third:
def is_member(array, value):
return array.count(value) > 0
Recursive solution:
def is_member(value, array):
if len(array) == 0:
return False
return value == array[0] or is_member(value, array[1:])
Using a generator expression (note that this in operator has nothing to do with the another one)
def is_member(x, a):
return any(x == y for y in a)
>>> is_member(10, xrange(1000000000000000))
True
You could simply just iterate over every element in the list then:
def is_member(col, a):
for i in xrange(len(col)):
if a == col[i]: return True
return False
>> a = [1,2,3,4]
>> is_member(a, 2)
True
>> is_member(a, 5)
False
Without using the "in" operator:
from itertools import imap
def is_member( item, array ):
return any( imap(lambda x: x == item, array ) )
which will cycle through the items of the list, one at a time, and short circuit when it hits a value that is True.
Well, there are a lot of ways to do this, of course -- but you're a little hamstrung by the prohibition of "in" anywhere in the code. Here are a few things to try.
Variations on a theme ...
def is_member(item, seq):
return sum(map(lambda x: x == item, seq)) > 0
def is_member(item, seq):
return len(filter(lambda x: x != item, seq)) != len(seq)
You may have heard that asking for forgiveness is better than asking for permission ...
def is_member(item, seq):
try:
seq.index(item)
return True
except:
return False
Or something a little more functional-flavored ...
import itertools, operator, functools
def is_member(item, seq):
not_eq = functools.partial(operator.ne, item)
return bool(list(itertools.dropwhile(not_eq, seq)))
But, since your requirements preclude the use of the looping construct which would be most reasonable, I think the experts would recommend writing your own looping framework. Something like ...
def loop(action, until):
while True:
action()
if until():
break
def is_member(item, seq):
seq = seq
sigil = [False]
def check():
if seq[0] == item:
sigil[0] = True
def til():
seq.remove(seq[0])
return not len(seq)
loop(check, til)
return sigil[0]
Let us know how it goes.

Categories

Resources