I need help with a Python homework, I need to write a quick sort code in OOP, what am I doing wrong, that it does not work?
class sort:
def __init__(self, array):
self.array = array
array = [4,3,1,3,5,6,4,67,7,5]
def quick_sort(array):
if len(array) <= 1:
return(array)
else:
smaller = []
bigger = []
pivot = array[0]
for number in array[1:]:
if number < pivot:
smaller.append(number)
else:
bigger.append(number)
return quick_sort(smaller) + [pivot] + quicksort(bigger)
return array
There's a few issues I can see:
Your quick_sort function starts from your class sort, so it must take as arguments (self, array).
Your liczba variable is not declared.
When returning your function, you should not call it again (Notion of recursion)
Related
I defined a function to change an element of a list to be number 0, if this element is not a number. It works using list comprehension but it doesn't work when I use a normal for loop.
I'm trying to understand what's is the error in the for loop.
See the code below:
def zerozero(mylist):
mylist = [0 if type(x) == str else x for x in mylist]
return mylist
def zerozero2(mylist):
for x in mylist:
if type(x) == str:
x = 0
else:
x = x
return mylist
Your second function is not quite equivalent. You would need something like this:
def zerozero2(mylist):
new_list = []
for x in mylist:
if type(x) == str:
new_list.append(0)
else:
new_list.append(x)
return new_list
In this manner you can mimic the functionality of the list comprehension, creating a new list and appending items to it as you iterate through.
If you want to modify your list 'in place', you can use this sort of construction:
for idx, x in enumearte(mylist):
if type(x) == str:
mylist[idx] = 0
else:
mylist[idx] = x
However, practically speaking this is unlikely to have much impact on your code efficiency. You can't do this with a list comprehension, and in either case you can just re-assign the new list back to your original variable when you return from the function:
mylist = zerozeroX(mylist)
So what happens is your function is returning the same list as your input.
What you should do is create an empty list first. For example my_list_0 = [].
def zerozero2(mylist):
my_list_0 = []
for x in mylist:
if type(x) == str:
x=0
else:
x=x
my_list_0.append(x)
return my_list_0
The list comprehension essentially returns the new values into your original list, so this is why it is different.
So far I have this
import random
numbers = []
for i in range(10):
numbers.append(random.randint(-100,100))
current_Min = 0
def minimum(x):
current_Min= numbers[0]
for i in numbers:
if i < current_Min:
current_Min = i
return current_Min
minimum(numbers)
print(numbers)
print(current_Min)
but it's not returning the minimum like I would like it too. Any help is appreciated.
Inside your def you should use the parameter x instead of numbers.
def minimum(x):
current_Min= x[0]
for i in x:
if i < current_Min:
current_Min = i
return current_Min
You should not use global variables here. The value of "current_Min" is different inside the function (due to Python's rules this is a local value) and outside the function (it is a global variable). Instead use the parameters, and the return value.
import random
def minimum(x):
current_Min= x[0]
for i in x:
if i < current_Min:
current_Min = i
return current_Min
numbers = []
for i in range(10):
numbers.append(random.randint(-100,100))
current_Min = minimum(numbers)
I am learning about recursive generators and found this program on web.
I undertand the recursive version of In-Order traversal but i am having trouble understanding recursive generator.
Specifically i am not able to understand
why 'yield x' is written in for loop?
Why 'yield x' is not collected in final list?
I have tried to dubug the generator and added the watch but i found that recursive call execute multiple time 'yield x' and it's not collected in final result.
class Tree:
def __init__(self, label, left=None, right=None):
self.label = label
self.left = left
self.right = right
def __repr__(self, level=0, indent=" "):
s = level*indent + repr(self.label)
if self.left:
s = s + "\\n" + self.left.__repr__(level+1, indent)
if self.right:
s = s + "\\n" + self.right.__repr__(level+1, indent)
return s
def __iter__(self):
return inorder(self)
def tree(list):
n = len(list)
if n == 0:
return []
i = n // 2
return Tree(list[i], tree(list[:i]), tree(list[i + 1:]))
# Recursive Generator
def inorder(t):
if t:
for x in inorder(t.left):
yield x
yield t.label
for x in inorder(t.right):
yield x
Role of yield x inside for loop.
Maybe what you don't understand is how the generator works? The generator is different from the iterator, it is not directly calculating the worthy collection, it is dynamically getting all the values. If the result of inorder(t.left) is not traversed by a for loop, then yield inorder(t.left) will return the entire generator created for t.left. Because your entire inorder function is a generator.
Unfortunately, I have not been able to find a specific description document. This is a description based on my experience. Others are welcome to make corrections to my opinion. If someone can provide a specific official description, welcome to add
Not sure exactly what you're looking for, but perhaps it is something along these lines:
class Tree:
def __init__(self, label, left=None, right=None):
self.label = label
self.left = left
self.right = right
def __repr__(self, level=0, indent=" "):
s = level*indent + repr(self.label)
if self.left:
s = s + "\n" + self.left.__repr__(level+1, indent)
if self.right:
s = s + "\n" + self.right.__repr__(level+1, indent)
return s
def __iter__(self):
return inorder(self)
def tree(list):
n = len(list)
if n == 0:
return []
i = n // 2
return Tree(list[i], tree(list[:i]), tree(list[i + 1:]))
def inorder(t):
if t:
for x in t.left:
yield x
yield t.label
for x in t.right:
yield x
t = tree("ABCDEFG")
[print(i.label) for i in t]
which outputs:
A
B
C
D
E
F
G
With that code you could instead:
[print('----------\n', i) for i in t]
which outputs each hierarchical node in the tree, from A to G.
Edit: If you're asking how generator works, perhaps this example could be enlightening:
>>> def list2gen(lst):
... for elem in lst:
... yield str(elem) + '_'
...
>>> print(list2gen([1,2,'7',-4]))
<generator object list2gen at 0x000001B0DEF8B0C0>
>>> print(list(list2gen([1,2,'7',-4])))
['1_', '2_', '7_', '-4_']
If your debugger breaks multiple times at a yield, but those elements never materialize in the resulting generator, you'd have to attribute that to bugs in the debugger. I've not used one for Python in more than a decade; they used to be notoriously bug-infested. In Python the paradigm is "test is king," and "avoid manual debugging," but I disagree with that. (The only reason I don't is lack of great IDE's and debuggers.)
Trying to multiply all the numbers in a stack, I originally thought of popping all elements into a list and then multiplying but wasn't sure how to/ if that was right.
this is my current code but I'm getting:
TypeError: 'method' object cannot be interpreted as an integer.
def multi_stack(s):
stack = Stack()
mult = 1
size = my_stack.size
for number in range(size):
tmp = my_stack.pop(size)
mult = mult * tmp
L.append(tmp)
for number in range(size):
my_stack.push(L.pop())
print(must)
I made a test case aswell
my_stack = Stack()
my_stack.push(12)
my_stack.push(2)
my_stack.push(4)
my_stack.push(40)
print(multi_stack(my_stack))
print(my_stack.size())`
this should print out :
3840
0
The Stack class I'm using
class Stack():
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def push(self,items):
return self.items.append(items)
def pop(self):
if self.is_empty() == True:
raise IndexError("The stack is empty!")
else:
return self.items.pop()
def peek(self):
if self.is_empty() == True:
raise IndexError("The stack is empty!")
else:
return self.items[len(self.items) - 1]
def size(self):
return len(self.items)
Python lists support append() and pop() methods that allow you to replicate LIFO stack behavior. Use append() to add to the end and pop() to remove the last element.
However, the underlying data structure is still a list. You can use many things to multiply a list together. for example, assuming a non-empty list:
import functools
mylist = [i for i in range(1, 10)]
product = functools.reduce(lambda x, y: x * y, mylist)
or
mylist = [i for i in range(1, 10)]
product = mylist[0]
for j in mylist[1:]:
product *= j
EDIT: Here is an example using your Stack class:
import functools
stack = Stack()
stack.push(1)
stack.push(3)
stack.push(9)
def multi_stack(s):
"""
s: a Stack() object
"""
return functools.reduce(lambda x, y: x * y, s.items)
def multi_stack_readable(s):
"""
s: a Stack() object
"""
if s.size() > 1:
product = s.items[0]
for i in s.items[1:]:
product *= i
return product
elif s.size() == 1:
return s.items
else:
raise IndexError("the stack is empty!")
print(multi_stack(stack))
print(multi_stack_readable(stack))
Using lambda functions is sometimes considered less readable, so I included a more readable version using a for loop. Both produce the same result.
Your code doesnt work because size = my_stack.size returns a method object and not the integer you expected; you forgot to add the parentheses at the end to actually call the method. So when you tried for number in range(size):, you get an exception because you are passing a method object instead of an integer to range(). There are also a bunch of other mistakes: you didnt use the parameter passed to the function at all, instead affecting global variable my_stack (unless that was your intent); you're performing operations on some unknown variable L; you created stack at the top of your function and did nothing with it, and so on. In general, too convoluted for such a simple goal. There are more efficient ways to do this but correcting your code:
def multi_stack(s):
mult = 1
size = s.size()
for i in range(size):
tmp = s.pop()
mult = mult * tmp
return mult
This should return your expected product, though it wont empty the stack. If you want to do that, then get rid of the function parameter, and substitute s for my_stack as before.
I have to define three functions: preorder(t):, postorder(t):, and inorder(t):.
Each function will take a binary tree as input and return a list. The list should then be ordered in same way the tree elements would be visited in the respective traversal (post-order, pre-order, or in-order)
I have written a code for each of them, but I keep getting an error when I call another function (flat_list()), I get an index error thrown by
if not x or len(x) < 1 or n > len(x) or x[n] == None:
IndexError: list index out of range
The code for my traversal methods is as follows:
def postorder(t):
pass
if t != None:
postorder(t.get_left())
postorder(t.get_right())
print(t.get_data())
def pre_order(t):
if t != None:
print(t.get_data())
pre_order(t.get_left())
pre_order(t.get_right())
def in_order(t):
pass
if t != None:
in_order(t.get_left())
print(t.get_data())
in_order(t.get_right())
def flat_list2(x,n):
if not x or len(x) < 1 or n > len(x) or x[n] == None:
return None
bt = BinaryTree( x[n] )
bt.set_left( flat_list2(x, 2*n))
bt.set_right(flat_list2(x, 2*n + 1))
return bt
this is how i call flat_list2
flat_node_list = [None, 55, 24, 72, 8, 51, None, 78, None, None, 25]
bst = create_tree_from_flat_list2(flat_node_list,1)
pre_order_nodes = pre_order(bst)
in_order_nodes = in_order(bst)
post_order_nodes = post_order(bst)
print( pre_order_nodes)
print( in_order_nodes)
print( post_order_nodes)
You should actually write three function that return iterators. Let the caller decide whether a list is needed. This is most easily done with generator functions. In 3.4+, 'yield from` can by used instead of a for loop.
def in_order(t):
if t != None:
yield from in_order(t.get_left())
yield t.get_data()
yield from in_order(t.get_right())
Move the yield statement for the other two versions.
First things first, I noticed that your indentation was inconsistent in the code block that you provided (fixed in revision). It is critical that you ensure that your indentation is consistent in Python or stuff will go south really quickly. Also, in the code below, I am assuming that you wanted your t.get_data() to still fall under if t != None in your postorder(t), so I have indented as such below. And lastly, I noticed that your method names did not match the spec you listed in the question, so I have updated the method names below to be compliant with your spec (no _ in the naming).
For getting the list, all you need to do is have your traversal methods return a list, and then extend your list at each level of the traversal with the other traversed values. This is done in lieu of printing the data.
def postorder(t):
lst = []
if t != None:
lst.extend(postorder(t.get_left()))
lst.extend(postorder(t.get_right()))
lst.append(t.get_data())
return lst
def preorder(t):
lst = []
if t != None:
lst.append(t.get_data())
lst.extend(preorder(t.get_left()))
lst.extend(preorder(t.get_right()))
return lst
def inorder(t):
lst = []
if t != None:
lst.extend(inorder(t.get_left()))
lst.append(t.get_data())
lst.extend(inorder(t.get_right()))
return lst
This will traverse to the full depths both left and right on each node and, depending on if it's preorder, postorder, or inorder, will append all the traversed elements in the order that they were traversed. Once this has occurred, it will return the properly ordered list to the next level up to get appended to its list. This will recurse until you get back to the root level.
Now, the IndexError coming from your flat_list, is probably being caused by trying to access x[n] when n could be equal to len(x). Remember that lists/arrays in Python are indexed from 0, meaning that the last element of the list would be x[n-1], not x[n].
So, to fix that, replace x[n] with x[n-1]. Like so:
def flat_list2(x,n):
if not x or len(x) < 1 or n < 1 or n > len(x) or x[n-1] == None:
return None
bt = BinaryTree( x[n-1] )
bt.set_left( flat_list2(x, 2*n))
bt.set_right(flat_list2(x, 2*n + 1))
return bt