python loops instead of recursion - python

I am a newbie in python .
Guys I have written one function which checks that the list is palindrome or not but I wanted to replace it with pure looping statements .Do u have any solution or do I have to use recursive function compulsorily .
import json
def reverse(x):
if isinstance(x, list):
return [reverse(x) for x in x[::-1]]
return x
def palindrome(x):
return x == reverse(x)
st=raw_input("Enter List : ")
lst=json.loads(st)
print palindrome(lst)

check this...
>>> def palindrome(n):
return n == n[::-1]
>>> palindrome('chk')
False
>>> palindrome('chc')
True
>>>

Check this out:
def is_palindrome(lst):
n = len(lst)
p, q = 0, n - 1
while p <= q:
pitem, qitem = lst[p], lst[q]
if isinstance(pitem, list) and isinstance(qitem, list):
if len(pitem) != len(qitem):
return False
if p == q:
lst[p:p+1] = pitem
q = p + len(pitem) - 1
else:
lst[p:p+1] = pitem
q += len(pitem) - 1
lst[q:q+1] = qitem
q += len(qitem) - 1
continue
elif pitem != qitem:
return False
p += 1;
q -= 1
return True
Above code also passes for nested list:
assert is_palindrome([1, 2, 3, 2, 1])
assert not is_palindrome([[0, 1]])
assert not is_palindrome([[0, 1, 1]])
assert is_palindrome([[0, 1, 0]])
assert is_palindrome([1, [1, 2], 3, [2, 1], 1])

You can do it with a simple loop:
def is_palindrome(s):
n = len(s)
for i in range(n / 2):
if s[i] != s[n - 1 - i]:
return False
return True
It's worth to mention, that above function uses only n / 2 comparisons and the below solution uses n comparisons:
def is_palindrome(s):
return s == s[::-1]

def palindrome(x):
q = [x]
while q:
x = q.pop()
if isinstance(x, list) and x:
if isinstance(x[0], list) and isinstance(x[-1], list):
q.append(x[0] + x[-1])
elif x[0] != x[-1]:
return False
q.append(x[1:-1])
elif isinstance(x, str):
q.append(list(x))
return True
def palindrome(x):
q = [x]
while q:
x = q.pop()
if isinstance(x, (str, list)):
for i in range(len(x) + 1 // 2):
if isinstance(x[i], list) and isinstance(x[-i-1], list):
q.append(x[i] + x[-i-1])
elif x[i] != x[-i-1]:
return False
return True
>>> palindrome('cat')
False
>>> palindrome('yay')
True
>>> palindrome([1, 2,3,[2],1])
False
>>> palindrome([1, [2,3,[4]],[[4],3,2],1])
True
>>> palindrome([[2,3], [2,3]])
False

Related

A string is the same if they have the same length and differ at most by one letter

how would this be done? I did it with def, but is there a simpler way to do it without def, lambda, enumerate and whatnot?
def is_one_away(first: str, other: str) -> bool:
skip_difference = {
-1: lambda i: (i, i+1),
1: lambda i: (i+1, i),
0: lambda i: (i+1, i+1),
}
try:
skip = skip_difference[len(first) - len(other)]
except KeyError:
return False
for i, (l1, l2) in enumerate(zip(first, other)):
if l1 != l2:
i -= 1
break
remain_first, remain_other = skip(i + 1)
return first[remain_first:] == other[remain_other:]
If I understand the problem correctly, the following should work:
def is_one_away(first,other):
return len(first) == len(other) and sum(x != y for x,y in zip(first,other)) <= 1
This is a clean versin of code that works.
def is_one_away(first: str, other: str) -> bool:
# check lengths
if len(first) != len(other):
return False
error_count = 0
for i in range(len(first)):
if first[i] != other[i]:
error_count += 1
if error_count > 1:
return False
return True
Here are some checks:
# some checks
a, b = 'hello', 'world'
result = is_one_away(a,b)
print(result)
a, b = 'hi', 'world'
result = is_one_away(a,b)
print(result)
a, b = 'world', 'world'
result = is_one_away(a,b)
print(result)
a, b = 'worlf', 'world'
result = is_one_away(a,b)
print(result)
a, b = 'worff', 'world'
result = is_one_away(a,b)
print(result)
Here is the result of the checks (as expected):
False
False
True
True
False

Valid position in array

else:
res = (numbers.index(str_pos[1:]), letters.index(str_pos[0]))
return res
def is_in_board(n,pos):
letters = [chr(x + ord('a')) for x in range(n)]
numbers = [str(x) for x in range(1, n + 1)]
numbers.reverse()
pos = ''.join([letters[pos[1]], numbers[pos[0]]])
if extract_pos(n,pos) is not None:
return True
else:
return False
How can I return False when the list (pos) index is out of range ?board
At the first line of the function extract_pos function you know all that you need:
The size of the plate: n x n
The desired indexes: str_pos
So I would do something like this at the first line of the extract_pos function:
if int(str_pos[0]) >= n or int(str_pos[1]) >= n or int(str_pos[0]) < 0 or int(str_pos[1]) < 0 :
return 'Out of index'
Then you have to check that return value in the is_in_board function:
extract_pos_return_value = extract_pos(n,pos)
if extract_pos_return_value is not None and extract_pos_return_value is not 'Out of index':
return True
else:
return False
Full Code:
def extract_pos(n, str_pos):
if int(str_pos[0]) >= n or int(str_pos[1]) >= n or int(str_pos[0]) < 0 or int(str_pos[1]) < 0 :
return 'Out of index'
letters = [chr(x + ord('a')) for x in range(n)]
numbers = [str(x) for x in range(1,n+1)]
numbers.reverse()
if len(str_pos) < 2 or str_pos[0] not in letters or str_pos[1] not in numbers:
res = None
else:
res = (numbers.index(str_pos[1:]), letters.index(str_pos[0]))
return res
def is_in_board(n,pos):
letters = [chr(x + ord('a')) for x in range(n)]
numbers = [str(x) for x in range(1, n + 1)]
numbers.reverse()
pos = ''.join([letters[pos[1]], numbers[pos[0]]])
extract_pos_return_value = extract_pos(n,pos)
if extract_pos_return_value is not None and extract_pos_return_value is not 'Out of index':
return True
else:
return False
I'll try to show you a simpler solution.
First, you do not need to construct lists for letters and for numbers, it is much easier to check the parameter.
Then in your is_in_board function you have not handled your pos parameter correctly.
Please check this solution:
def extract_pos(n, str_pos):
if 1<=ord(str_pos[0])-ord('a')<=n and 1<=ord(str_pos[1])-ord('0')<=n:
return n-int(str_pos[1]), (ord(str_pos[0])-ord('a'))
else:
return None
def is_in_board(n, pos):
xpos = extract_pos(n,chr(pos[1]+ord('a'))+chr(8-pos[0]+ord('0')))
if xpos != None:
x, y = xpos
if 0<=x<n and 0<=y<n:
return True
return False

Fibonacci that takes a list of numbers and returns their fibonacci number

I am trying to implement a function that will print a number of fibonacci numbers. For example if my input was fibonacci([0,1,2,3], the output would be 0,1,1,2.
I am not sure how to proceed.
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
return fibonacci(n - 1) + fibonacci(n-2)
while True:
n.append(n)
print(fibonacci[5,10,11])
You can refactor your code a bit and get:
def fibonacci(lst):
def getTerm(n):
if n == 0:
return 0
elif n == 1:
return 1
return getTerm(n - 1) + getTerm(n-2)
return [getTerm(x) for x in lst]
Gives output:
>>> fibonacci([0,1,2,3])
[0, 1, 1, 2]
>>> fibonacci([5,10,11])
[5, 55, 89]
Avoiding redundant computations:
def fibonacci(indices):
fibs = {}
set_of_indices = set(indices)
f0 = fibs[0] = 0
f1 = fibs[1] = 1
for i in range(2,max(indices)+1):
f2 = f0+f1
if i in set_of_indices:
fibs[i] = f2
f0,f1=f1,f2
return [fibs[i] for i in indices]

Python: represent a number as a sum of prime numbers

I need to write an algorithm, that can represent a number as a min sum of prime numbers:
For example:
8 -> [2, 2, 2, 2], [3, 5], [2, 3, 3]
and I need get min len of this => 2
I've written the code, but it takes a lot of time, because it contains recursion. How can I change it to improve time?
import sys
x = int(sys.stdin.readline())
def is_prime(n):
for i in range(2, n):
if n % i == 0:
return False
return True
def decomposition(x):
result = []
for a in range(2, int(x/2 + 1)):
if x-a >= 2:
b = x - a
pair = [a, b]
result.append(pair)
return result
def f(elem):
list_of_mins = []
if is_prime(elem) == True:
return 1
else:
pairs = decomposition(elem)
print(pairs)
for a,b in pairs:
list_of_mins.append(f(a)+f(b))
return min(list_of_mins)
if str(int(x)).isdigit() and 2 <= int(x) <= 10 ** 9:
sum = []import sys
x = int(sys.stdin.readline())
def is_prime(n):
for i in range(2, n):
if n % i == 0:
return False
return True
def decomposition(x):
result = []
for a in range(2, int(x/2 + 1)):
if x-a >= 2:
b = x - a
pair = [a, b]
result.append(pair)
return result
def f(elem):
list_of_mins = []
if is_prime(elem) == True:
return 1
else:
pairs = decomposition(elem)
print(pairs)
for a,b in pairs:
list_of_mins.append(f(a)+f(b))
return min(list_of_mins)
if str(int(x)).isdigit() and 2 <= int(x) <= 10 ** 9:
sum = []
print(f(x))
Your is_prime function only needs to test divisors up to pow(n, 0.5)+1. This means your code would be:
def is_prime(n):
for i in range(2, int(pow(n, 0.5)+1):
if n % i == 0:
return False
return True
This should speed your algorithm up significantly.
Here's a possible solution:
import math
class Foo():
def __init__(self, n):
self.n = n
self.primes = self.prime_sieve(n)
def prime_sieve(self, sieve_size):
sieve = [True] * sieve_size
sieve[0] = False
sieve[1] = False
for i in range(2, int(math.sqrt(sieve_size)) + 1):
pointer = i * 2
while pointer < sieve_size:
sieve[pointer] = False
pointer += i
primes = []
for i in range(sieve_size):
if sieve[i] == True:
primes.append(i)
return primes
def sum_to_n(self, n, size, limit=None):
if size == 1:
yield [n]
return
if limit is None:
limit = n
start = (n + size - 1) // size
stop = min(limit, n - size + 1) + 1
for i in range(start, stop):
for tail in self.sum_to_n(n - i, size - 1, i):
yield [i] + tail
def possible_sums(self):
for i in range(2, self.n):
result = list(self.sum_to_n(self.n, i))
result = (
[v for v in result if all([(p in self.primes) for p in v])])
if result:
yield result
def result(self):
for i in self.possible_sums():
return i
raise Exception("Not available result!")
if __name__ == '__main__':
obj = Foo(8)
print(list(obj.possible_sums()))
print('-' * 80)
try:
v = obj.result()
print("{} , length = {}".format(v[0], len(v[0])))
except Exception as e:
print(e)
Result:
[[[5, 3]], [[3, 3, 2]], [[2, 2, 2, 2]]]
--------------------------------------------------------------------------------
[5, 3] , length = 2

Print only one list in recursion

In the following code, I return the integer value for the amount of consecutive numbers in a given string.
def consecutive_length(S):
if S == '':
return 0
if len(S) == 1:
return 1
if S[0] == S[1]:
return 1 + consecutive_length(S[1:])
return 1
def compress(S):
if S == '':
return 0
cons_length = consecutive_length(S)
return [cons_length] + [compress(S[cons_length:])]
When I run this print statement, the following is returned:
>>> print (compress('1111000000001111000111111111111111'))
[4, [8, [4, [3, [15, 0]]]]]
Where I really want the following to be returned:
>>> print (compress('1111000000001111000111111111111111'))
[4, 8, 4, 3, 15]
An alternative to your method is to use itertools.groupby():
from itertools import groupby
s = '1111000000001111000111111111111111'
answer = [len([digit for digit in group[1]]) for group in groupby(s)]
print(answer)
Output
[4, 8, 4, 3, 15]
Here you go:
def consecutive_length(S):
if S == '':
return 0
if len(S) == 1:
return 1
if S[0] == S[1]:
return 1 + consecutive_length(S[1:])
return 1
def compress(S):
if S == '':
return []
cons_length = consecutive_length(S)
return [cons_length] + compress(S[cons_length:])
When you return a list, [what_is_returned] will be a nested list, but when you return an integer, it will be just a list. Instead, (in compress()) ,always return a list, and remove the brackets when you use what it returns:
def consecutive_length(S):
if S == '':
return 0
if len(S) == 1:
return 1
if S[0] == S[1]:
return 1 + consecutive_length(S[1:])
return 1
def compress(S):
if S == '':
return []
cons_length = consecutive_length(S)
return [cons_length] + compress(S[cons_length:])

Categories

Resources