how to multiply all numbers in a stack - python-3.x

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.

Related

Add two numbers works in Jupyter, but generates a wrong answer in LeetCode

I'm trying the "add two numbers" (linked list) problem in leetcode. The code that I wrote works fine in Jupyter notebook and returns the correct answer:
def list_to_digits(lst):
lst.reverse()
strings = map(str, lst)
a_string = "". join(strings)
an_integer = int(a_string)
return an_integer
def Convert_IntegersToList(integers):
res = list(map(int, str(integers)))
res.reverse()
return(res)
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
integered_l1 = self.list_to_digits(l1)
integered_l2 = self.list_to_digits(l2)
sum_Integers = integered_l1 + integered_l2
list_ofSum = self.Convert_IntegersToList(sum_Integers)
return(list_ofSum)
For example, for the following:
l1 = [2,4,3]
l2 = [5,6,4]
output_list = Solution().addTwoNumbers(l1,l2)
print(output_list)
this code returns: [7, 0, 8] which is the correct result. When I run the same code in leetcode however, it returns the following error:
ListNode object has no attribute reverse
this error happens in line lst.reverse() from function list_to_digits.
Then I tried using two functions for converting between nodeList and python list according to here. This time, I have something like this:
class Solution:
def listnode_to_pylist(self, listnode):
ret = []
while True:
ret.append(listnode.val)
if listnode.next != None:
listnode = listnode.next
else:
return ret
def pylist_to_listnode(self, pylist, link_count):
if len(pylist) > 1:
ret = precompiled.listnode.ListNode(pylist.pop())
ret.next = self.pylist_to_listnode(pylist, link_count)
return ret
else:
return precompiled.listnode.ListNode(pylist.pop(), None)
def list_to_digits(self, lst):
lst.reverse()
strings = map(str, lst)
a_string = "". join(strings)
an_integer = int(a_string)
return an_integer
def Convert_IntegersToList(self, integers):
res = list(map(int, str(integers)))
res.reverse()
return(res)
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
l1_ = self.listnode_to_pylist(l1)
l2_ = self.listnode_to_pylist(l2)
integered_list1 = self.list_to_digits(l1_)
integered_list2 = self.list_to_digits(l2_)
sum_Integers = integered_list1 + integered_list2
list_ofSum = self.Convert_IntegersToList(sum_Integers)
return(self.pylist_to_listnode(list_ofSum, len(list_ofSum)))
This code works in leetCode, but it returns the resulting list in the reverse order. For example, for the above example it returns: [8,0,7] (and I tried removing the list reverse line, but still the returned list is in the reverse order). Interestingly, when I run the modified code in Jupyter notebook, it throws the following error:
AttributeError: 'list' object has no attribute 'val'
I cannot figure out what I'm doing wrong in each of these situations and how to fix it. Any idea how I can correct each of these two codes such that it works in leetcode and how to fix the error for the latter code in Jupyter notebook?

Python: How can I change a function's argument value from an inner frame?

In the example below, force should change the value of the parameter x of the double function. ValidateAndCast checks the given parameter and casts it. So in this case, after force returns, x should be 2, and thus the return value of double should be 4. Assume that all the altering is done in the force function.
How do I achieve this? I've looked into inspect so far and will continue studying.
def is_number(x):
try:
float(x)
return True
except:
return False
def to_int(x):
return int(float(x))
def double(x):
force(x=ValidateAndCast(is_number, to_int))
return x * 2
x = '2.54'
y = double(x)
print(y)
This solution works for me.
import ctypes
import inspect
def change():
def apply(frame):
frame.f_locals['x'] = 4
ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame), ctypes.c_int(1))
calling_frame = inspect.stack()[1][0]
apply(calling_frame)
def f(x):
change()
return x * 2
y = f(2)
print(y) # prints 8

Python: Unexpected result in a recursive function

I've written a recursive function to gauge, e.g. list depth and for some reason it returns unexpected results.
I have two functions:
1. checks if the object is iterable
2. gauges the depth of the object, e.g. list
I think I'm missing something in the second function but I couldn't wrap my head around why exactly variable n when returned from else turns into a funny result.
I set print to see how n gets changed in every stage and it seemed working as expected but when returned from else it turns into a wrong number.
Here are two functions' code:
def isiterable(obj):
'''
takes in an obj and returns 1 if iterable or 0 if not
strings are discarded as iterable
:param obj: any object
:return: int
'''
if isinstance(obj, str):
return 0
else:
try:
iter(obj)
return 1
except TypeError as err:
return 0
my second function is recursive where I'm experiencing problems
def get_depth(a, n=0):
if isiterable(a):
return n + f(a[0], n+1)
else:
return n
I've three examples:
a = [[[1,2], [3,4]], [[5,6],[7,8]]]
b = [[1,2], [2,3]]
c = [2]
I'm expecting get_depth to return 3 for list a, 2 for list b and 1 for list c.
for some reason results for a get doubled and return 6. In b case it is 3 instead of 2.
Many thanks
You don't need to add n when you return from get_depth.
def get_depth(a, n=0):
if isiterable(a):
return get_depth(a[0], n+1)
else:
return n
Because, when a have more depth, you will calculate the get_depth function again witn n+1 which is already count the depth correctly and the extras are not needed.
Btw, you have to think about what if this case?
d = [1, 2, [3, 4]]
I can modify a bit such as:
def get_depth(a, n=0):
if isiterable(a):
temp = []
for i in range(0, len(a)):
temp.append(get_depth(a[i], n+1))
return max(temp)
else:
return n

OOP Quicksort in Python

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)

Tree traversals python

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

Resources