Python - Iterative searchtree implementation - python

I am trying to implement an iterative function, which searches a given search-tree for an integer, and reports back whether that integer exist within the search-tree.
So far it works for returning True if the value exists, but runs into a "list index out of range" error when searching for values not existant within the search-tree.
return [l,v,r]
def left(l) :
return l[0]
def right(l) :
return l[2]
def value(l) :
return l[1]
def empty() :
return []
def iterative_check_for_elem(val,tree):
while not tree == False:
if val == value(tree):
return True
break
elif val < value(tree):
tree = left(tree)
elif val > value(tree):
tree = right(tree)
return False
test_tree = node(node(node(empty(),30,empty()),40,node(empty(),45,empty())),50,node(node(empty(),55,empty()),60,node(empty(),70,empty())))
print(iterative_check_for_elem(45,test_tree))
45 works in the call to print, 47 runs into the error.
I can not figure out what is going wrong honestly.

Your tree has a bunch of empty nodes in it (created by empty()), and your search code doesn't deal with them properly. While an empty list is falsey, it's not equal to False, which your code seems to expect. Try rewriting the loop condition as:
while tree:
...
Or you could be more explicit and do a check like:
while len(tree) > 0:
...

Related

Python recursively jumping through a list by a given index jump or less while avoiding zeros

I am trying to write a function that has only one argument, a list of positive integers.
It has to be recursive and find whether you can get from the start to the end while avoiding landing on 0s. It has to start at first value list[0] but you can jump by either the full amount or less.
For example
list1 = [3,1,2,0,4,0,1]
list2 = [3,2,1,0,2,0,2]
List 1 should return True as you can jump from 3 to 2 to 4 to 1.
List 2 should return False as it does not matter how you jump, you will land at the first 0.
Here is my attempt so far:
def check_level(level):
jump = level[0]
if level[-1] == 0:
return False
elif jump == 0:
return False
elif jump == 0:
return False
elif len(level) > 1:
if level[jump] > len(level):
return True
elif level[-1] == 0:
return False
elif level[0] != 0:
if level[jump] == 0:
level[0] -= 1
return check_level(level)
else:
jump_index = level.index(level[jump])
new_level = level[jump_index:]
return check_level(new_level)
else:
return True
It does not work with all examples and with others it comes up with an error:
if level[jump] > len(level):
TypeError: '>' not supported between instances of 'list' and 'int'```
I am out of ideas on how to approach this and whether my approach is failed from the start... I hate recursion, hence I need to practice it.
The general logic is:
"If you can jump to a True position, the current position is also True"
Implemented like this:
def checklevel(lst):
if not lst:
# no list is True (we are done)
return True
return any( checklevel(lst[i:]) for i in range(1,lst[0]+1))
list1 = [3,1,2,0,4,0,1]
list2 = [3,2,1,0,2,0,2]
assert checklevel(list1)
assert not checklevel(list2)
Note that this is a terrible solution for large lists, you should try a iterative dp-table in that case.
After advancing by a number of positions, you simply have to recurse with the rest of the list. Do it for distances from 1 to the value of the first element and you're done:
def jumpable(A):
if not A: return True # reaching end wins
return any(jumpable(A[i+1:]) for i in range(A[0])) # try all distances
ouput:
print(jumpable([3,1,2,0,4,0,1])) # True
print(jumpable([3,2,1,0,2,0,2])) # False
To avoid creating memory wasting temporary lists you can pass an index down (instead of a sublist) and use it as the starting point for the next level of recursion:
def jumpable(A,i=0):
if i>=len(A) : return True # reaching end
return any(jumpable(A,i+j+1) for j in range(A[i])) # try all distances
With a default value for i=0, you function still has only one parameter when called from the outside.

What would make a Boolean return value change after it's returned?

In this recursive code, i'm getting the function to properly return True, but then it proceeds for 1 additional step and changes the return value to "None". I believe I don't understand return values properly. Can someone tell me why this is happening? Thank you in advance.
--
def nestedListContains(NL, target):
for i in range(0, len(NL)):
if type(NL[i]) == int:
if NL[i] == target:
return True
elif i == (len(NL) - 1):
return False
elif type(NL[i]) != int:
nestedListContains(NL[i], target)
nestedListContains([[9, 4, 5], [3, 8]], 3) #Test Case#
There are three problems with your code; first, you do nothing with the result of the recursive call. Second, you should use isinstance() to check if a value is of some type, not type(ob) ==. Third, instead of using range() and check i to see if the last value was reached, just return False after the loop if nothing was found.
In total:
def nestedListContains(NL, target):
for value in NL:
if isinstance(value, int):
test = value == target
else:
# value is not an int, so it's a list
test = nestedListContains(value, target)
if test:
return True # found target
return False # We finished the loop without finding target
This will throw a TypeError if NL isn't a list at all. Which is perhaps an even better check than isinstance() -- if it can be iterated then it's a list, and if iteration throws a TypeError it's something we should compare to target. I'll also make the naming a bit more standard:
def nested_list_contains(nested_list, target):
try:
for value in nested_list:
if nested_list_contains(value, target):
return True
return False
except TypeError:
# It's a single value
return nested_list == target
But there's an even better way. What we really want to do is flatten the nested list, and check to see if the target is in it. We can turn the above into a generator that flattens iterables recursively:
def flatten_nested_list(nested_list):
try:
for v in nested_list:
for flattened in flatten_nested_list(v):
yield flatten
except TypeError:
yield nested_list
def nested_list_contains(nested_list, target):
return target in flatten_nested_list(nested_list)
To use recursion you have to return your recursive result:
def nestedListContains(NL, target):
for i in range(0, len(NL)):
if type(NL[i]) == int:
if NL[i] == target:
return True
elif i == (len(NL) - 1):
return False
elif type(NL[i]) != int:
#you missed the return for the recursive case
ret = nestedListContains(NL[i], target)
if(type(ret) == bool): #ensure we have an actual result and not a fall through
return ret
To elaborate a little on the earlier answer, you get None when you reach the end of the function without returning a specific value:
def func():
... do something ...
is equivalent to:
def func():
... do something ...
return None
This will still happen if you pass in an empty NL, since there's no return statement after the loop.
(also, isinstance(value, int) is the preferred way to check the type of something)

Search function python

Hi Im trying to create a search function in python, that goes through a list and searches for an element in it.
so far ive got
def search_func(list, x)
if list < 0:
return("failure")
else:
x = list[0]
while x > list:
x = list [0] + 1 <---- how would you tell python to go to the next element in the list ?
if (x = TargetValue):
return "success"
else
return "failure"
Well, you current code isn't very Pythonic. And there are several mistakes! you have to use indexes to acces an element in a list, correcting your code it looks like this:
def search_func(lst, x):
if len(lst) <= 0: # this is how you test if the list is empty
return "failure"
i = 0 # we'll use this as index to traverse the list
while i < len(lst): # this is how you test to see if the index is valid
if lst[i] == x: # this is how you check the current element
return "success"
i += 1 # this is how you advance to the next element
else: # this executes only if the loop didn't find the element
return "failure"
... But notice that in Python you rarely use while to traverse a list, a much more natural and simpler approach is to use for, which automatically binds a variable to each element, without having to use indexes:
def search_func(lst, x):
if not lst: # shorter way to test if the list is empty
return "failure"
for e in lst: # look how easy is to traverse the list!
if e == x: # we no longer care about indexes
return "success"
else:
return "failure"
But we can be even more Pythonic! the functionality you want to implement is so common that's already built into lists. Just use in to test if an element is inside a list:
def search_func(lst, x):
if lst and x in lst: # test for emptiness and for membership
return "success"
else:
return "failure"
Are you saying you want to see if an element is in a list? If so, there is no need for a function like that. Just use in:
>>> lst = [1, 2, 3]
>>> 1 in lst
True
>>> 4 in lst
False
>>>
This method is a lot more efficient.
If you have to do it without in, I suppose this will work:
def search_func(lst, x):
return "success" if lst.count(x) else "failure"
you dont need to write a function for searching, just use
x in llist
Update:
def search_func(llist,x):
for i in llist:
if i==x:
return True
return False
You are making your problem more complex, while solving any problem just think before starting to code. You are using while loops and so on which may sometimes becomes an infinite loop. You should use a for loop to solve it. This is better than while loop. So just check which condition helps you. That's it you are almost done.
def search_func(lst,x):
for e in lst: #here e defines elements in the given list
if e==x: #if condition checks whether element is equal to x
return True
else:
return False
def search(query, result_set):
if isinstance(query, str):
query = query.split()
assert isinstance(query, list)
results = []
for i in result_set:
if all(quer.casefold() in str(i).casefold() for quer in query):
results.append(i)
return results
Works best.

How can I use recursion to find palindromes using Python?

I've just started exploring the wonders of programming. I'm trying to write a code to identify numeric palindromes. Just looking at numbers and not texts. I'm trying to learn to use recursion here. But I'm just not getting anywhere and I can't figure out what's wrong with it.
My idea was to check first string vs the last, then delete these two if they match, and repeat. Eventually there'll be nothing left (implying it is a palindrome) or there will be a couple that doesn't match (implying the reverse).
I know there are better codes to finding palindromes in but I just wanted to try my hand at recursion.
So what's wrong?
def f(n):
global li
li=list(str(n))
if (len(li)==(1 or 0)):
return True
elif li[len(li)-1]==li[0]:
del li[0]
del li[len(li)-1]
if len(li)==0:
return True
if len(li)>0:
global x
x=''.join(li)
str(x)
f(x)
else:
return False
Thanks in advance!
A few comments
Why are x and li globals? In recursion, all variables should be local.
Why are you converting back and forth between str and list? You can subscript both of them
You need to return the result of your recursive call: return f(x)
Try these suggestions, and see how it works out.
Before looking into it too much, if (len(li)==(1 or 0)): doesn't do what you're expecting it to do. (1 or 0) will always evaluate to 1.
You probably want:
if len(li) in (1, 0):
There are a couple of problems with your solution. Let me analyse them line by line.
You don't need global statements if you don't intend to change variables outside of function scope. Thus, I removed two lines with global from your code.
li=list(str(n)): casting a string to a list is unnecessary, as a string in Python has a similar interface to an immutable list. So a simple li = str(n) will suffice.
if (len(li)==(1 or 0)):: although it looks OK, it is in fact an incorrect way to compare a value to a few other values. The or operator returns the first "true" value from its left or right operand, so in this case it always returns 1. Instead, you can use the in operator, which checks whether the left operand is an element of a right operand. If we make the right operand a tuple (1, 0), all will be well. Furthermore, you don't need parentheses around the if statement. You should write: if len(li) in (1, 0):
elif li[len(li)-1]==li[0]: is fine, but we can write this shorter in Python, because it supports negative list indexing: elif li[-1] == li[0]:
Because we don't use lists (mutable sequences) because of point 2., we can't do del li[0] on them. And anyway, removing the first element of a list is very inefficient in Python (the whole list must be copied). From the very same reason, we can't do del li[len(li)-1]. Instead, we can use the "splicing" operator to extract a substring from the string: li = li[1:-1]
if len(li)==0: is unnecessary long. In Python, empty strings and lists resolve to False if tested by an if. So you can write if not li:
if len(li)>0:: You don't have to check again if li is not empty -- you checked it in point 6. So a simple else: would suffice. Or even better, remove this line completely and unindent the rest of the function, because the body of the if in 6. contains a return. So if we didn't enter the if, we are in the else without writing it at all.
x=''.join(li): We don't need to convert our string to a string, because of the decision made in 2. Remove this line.
str(x): This line didn't do anything useful in your code, because str() doesn't modify its argument in place, but returns a new value (so x = str(x) would have more sense). You can also remove it.
f(x): This is a valid way to call a recursive function in Python, but you have to do something with its value. Return it perhaps? We'll change it to: return f(li) (as we don't have an x variable any more).
We end up with the following code:
def f(n):
li = str(n)
if len(li) in (1, 0):
return True
elif li[-1] == li[0]:
li = li[1:-1]
if not li:
return True
return f(li)
else:
return False
It's almost what we need, but still a little refinement can be made. If you look at the lines if not li: return True, you'll see that they are not necessary. If we remove them, then f will be called with an empty string as the argument, len(li) will equal 0 and True will be returned anyway. So we'll go ahead and remove these lines:
def f(n):
li = str(n)
if len(li) in (1, 0):
return True
elif li[-1] == li[0]:
li = li[1:-1]
return f(li)
else:
return False
And that's it! Good luck on your way to becoming a successful programmer!
Split the whole show out into a list, then just:
def fun(yourList):
if yourList.pop(0) == yourList.pop(-1):
if len(yourList) < 2:
return True # We're a palindrome
else:
return fun(yourList)
else:
return False # We're not a palindrome
print "1234321"
print fun(list("1234321")) # True
print "6234321"
print fun(list("6234321")) # False
def palindrome(n):
return n == n[::-1]
It's hard to tell what you intend to do from your code, but I wrote a simpler (also recursive) example that might make it easier for you to understand:
def is_palindrome(num):
s = str(num)
if s[0] != s[-1]:
return False
elif not s[1:-1]:
return True
else:
return is_palindrome(int(s[1:-1]))
number = int(raw_input("Enter a number: "))
rev = 0
neg = number
original = number
if (number < 0):
number = number * -1
else:
number = number
while ( number > 0 ):
k = number % 10
number = number / 10
rev = k + ( rev * 10 )
if (number < 1):
break
if ( neg < 0 ):
rev = ( rev * -1)
else:
rev = (rev)
if ( rev == original):
print "The number you entered is a palindrome number"
else:
print "The number you entered is not a palindrome number"
This code even works for the negative numbers i am new to programming in case of any errors
dont mind.

Recursion and return statements [duplicate]

This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 8 months ago.
I'm fairly new to Python and recursive functions as a whole, so pardon my ignorance.
I am trying to implement a binary search tree in Python and have the following insert method (taken out of a class):
def insert(self, key, root=None):
'''Inserts a node in the tree'''
if root == None:
root = self.root
if root.key == None:
self._update(root, key)
return 0
else:
tmp = root
if key > tmp.key: # we work with the right subtree
self.insert(key, root=tmp.right)
elif key < tmp.key: # we work with the left subtree
self.insert(key, root=tmp.left)
else: # key already exists
return 0
I'm not sure if this is legible, but it traverses the tree until it gets to a None value and updates the node with the key to insert.
Now, the method works nicely and correctly creates a BST from scratch. But there's a problem with the return statements, as it only returns 0 if there is no recursion performed.
>>> bst.insert(10)
0
>>> bst.insert(15)
>>> bst.root.right.key
15
>>>
"Inserting" the root key again returns 0 (from line 15) the way it should.
>>> bst.insert(10)
0
I can't figure out why this happens. If I put a print statement in line 6, it executes correctly, yet it just won't return anything past the first insertion. Why is this? (I'm pretty sure I'm missing some basic information regarding Python and recursion)
Thanks for your help,
Ivan
P.S.: I've read that recursion is not the best way to implement a BST, so I'll look into other solutions, but I'd like to know the answer to this before moving on.
On your recursive lines, you do not return anything. If you want it to return 0, you should replace them with lines like:
return self.insert(key, root=tmp.left)
instead of just
self.insert(key, root=tmp.left)
You are inside a function and want to return a value, what do you do? You write
def function():
return value
In your case you want to return the value returned by a function call, so you have to do.
def function():
return another_function()
However you do
def function():
another_function()
Why do you think that should work? Of course you use recursion but in such a case you should remember the Zen of Python which simply says:
Special cases aren't special enough to break the rules.
You need a return statement in your recursive case. Try this adjustment.
def insert(self, key, root=None):
'''Inserts a node in the tree'''
if root == None:
root = self.root
if root.key == None:
self._update(root, key)
return 0
else:
tmp = root
if key > tmp.key: # we work with the right subtree
return self.insert(key, root=tmp.right)
elif key < tmp.key: # we work with the left subtree
return self.insert(key, root=tmp.left)
else: # key already exists
return 0

Categories

Resources