Reversing a Stack in Python - python

To reverse a stack:
I made a empty temporary stack
I used tempstack.push(stack.pop())
and then renamed it to stack = tempstack
but it doesn't seem to work. Any idea why?
To call this, I want to use just reverse(stack), not stack = reverse(stack).
def reverse(stack):
new_stack = Stack()
while not stack.is_empty():
new_stack.push(stack.pop())
stack = new_stack

If you're using actual lists to implement stacks (that is, if Stack inherits from list or basically is a list), then simply reverse the list in-place:
def reverse_stack(stack):
stack.reverse()
I renamed the function to reverse_stack just to avoid confusion; you could still call it reverse. Example:
>>> stack = [1, 2, 3]
>>> reverse_stack(stack)
>>> stack
[3, 2, 1]
However, it seems that your Stack class doesn't inherit from list but keeps the underlying list in a private attribute, so you can't directly use any of the MutableSequence API on a Stack. Hence,
Version2, using only is_empty, push and pop methods of Stack
and using only Stacks, not lists or deques etc. First, a couple of helper functions:
def reverse_copy_stack(stack, rev_stack=None):
'''Return a reversed copy of stack, which is emptied.
rev_stack receives the reversed copy if it's not None
'''
if rev_stack is None:
rev_stack = Stack()
while not stack.is_empty():
rev_stack.push(stack.pop())
return rev_stack
def copy_stack(stack):
'''Return a copy of stack, which is emptied.'''
return reverse_copy_stack( reverse_copy_stack(stack))
Now we can implement reverse_stack:
def reverse_stack(stack):
'''Reverse stack in-place'''
new_stack = copy_stack(stack)
# Empty stack
while not stack.is_empty():
stack.pop()
# put reversed copy of new_stack in stack
reverse_copy_stack(new_stack, stack)

As others pointed out, the last assignment doesn't do anything. However, the idea behind the exercise here is probably to only use the standard stack primitives push, pop, and is_empty, without relying on the exact stack implementation to make use of list.reverse and such.
The key point to notice is that stack is a last-in-first-out structure, so reading its contents automatically produces them in the reverse order. This is why a solution that uses another stack for temporary storage doesn't work:
def reverse(stack):
# Doesn't work
temp = Stack()
while not stack.is_empty():
temp.push(stack.pop())
while not temp.is_empty():
stack.push(temp.pop())
Here the stack contents get reversed twice: once when reading them from the original stack, and once when reading them from the temporary stack, so you end up with stack contents in the original order. To actually reverse a stack, you need extract the items into a list and then traverse it in order (from beginning to end), pushing the items on the original stack as they come:
def reverse(stack):
items = []
while not stack.is_empty():
items.append(stack.pop())
for item in items:
stack.push(item)
Edit: inspired by BrianO's answer, here is a version that doesn't use a list at all (but does instantiate two temporary stacks):
def reverse(stack):
tmp1 = Stack()
while not stack.is_empty():
tmp1.push(stack.pop())
tmp2 = Stack()
while not tmp1.is_empty():
tmp2.push(tmp1.pop())
while not tmp2.is_empty():
stack.push(tmp2.pop())
Here the idea is to make use of the fact that copying the stack does reverse the contents - it's just that copying it back reverses it again. So we just copy it three times, first from the original stack to a temporary stack, then from a temporary stack to another temporary stack, and finally from the other temporary stack to the original stack. Reversing the contents three times ends up with the original contents reversed, which was required.

Add a return value
def reverse(stack):
new_stack = Stack()
while not stack.is_empty():
new_stack.push(stack.pop())
return new_stack
and when calling the function do this:
stack = reverse(stack)
You are assigning value to stack inside function but not from where you called it. Issues with scope.

It looks like you should have written while not stack.is_empty():
(After the edit) Ok, now instead of stack = new_stack, it should say return new_stack. The function should be called with stack = reverse(stack).
(Responding to comments) If returning a value is not an option, then we need to know what methods there are to modify Stack objects. Saying stack = new_stack or stack = Stack() will not change it outside of the function.
Something like this should work:
def reverse(stack):
new_stack = Stack()
while not stack.is_empty():
new_stack.push(stack.pop())
stack._items = new_stack._items
However it's probably a bad idea because the underscore in front of _items shows that whoever wrote the Stack class didn't want it to be used that way.
Plus as #user4815162342 pointed out, this presumably reverses the stack twice, so instead of using a temporary new_stack = Stack() we should just use a temporary list. Really #user4815162342's answer is the best one.

If the Stack class is yours or you can extend it, then another way of reversing the stack would be to keep all the data intact, and keep track of which way up your stack is (growing up or down) and either push/pop to the top or the bottom of the stack depending on the stack direction. Your stack reverse method is then simply a case of changing the flag which determines whether your stack grows up or down.
I don't have any code as yet, but if your stack is large then changing a flag may well be far simpler than reversing a large list of data.

class Stack():
def __init__(self):
self.item=[]
self.n=0
def __len__(self):
return self.n
def isEmpty(self):
return self.n==0
def push(self,item):
self.item.append(item)
self.n+=1
def pop(self):
ele=self.item.pop()
self.n-=1
return ele
def getPeek(self):
if self.n>0:
return self.item[-1]
return "Stack is empty"
def getStackitem(self):
return [self.item[i] for i in range(self.n)]
def reversing(data):
x=Stack()
for i in data:
x.push(i)
y=Stack()
while not x.isEmpty():
y.push(x.pop())
return "".join(y.getStackitem())
print(reversing("123456789"))

Copy the stack first, empty the original stack, then follow your method.
def reverse(stack):
old_stack = stack[:]
while not stack.is_empty():
stack.pop()
while not old_stack.is_empty():
stack.push(old_stack.pop())

Related

Error when using __iter__ and __next__ with a Python linked list? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
def __iter__(self):
return self
def __next(self):
if self.head is None:
raise StopIteration
else:
return self.head.next
Basically I attempted these implementation of the methods based on a basic example for W3 schools. It doesn't like that iter is returning an object type of the LinkedList.
Error:
TypeError: iter() returned non-iterator of type 'LinkedList' linked list
If I try to return self.head, it doesn't like that it is a node object?
Error:
TypeError: iter() returned non-iterator of type 'Node'
I am trying to make my LinkedList iterable with a forloop, but am having a hard time.
Does anyone know the correct implentation to make a LinkedList iterable in Python? Similar questions on here do not make sense to me and the solutions don't work for my usage.
The dunder method for the next item is __next__ rather than __next, and you seem to be missing code that actually moves through the list as you iterate.
The normal method I use is to have a separate iterator class within the type to do the grunt work. In addition, the way you have your list set up makes the idea of an element class desirable as well (were you using a Python list, this would not be needed but, since you want an item and next "pointer", it's better as a separate class).
Let's start by creating the list class with an enclosed item class:
class MyList:
# Single element in the list.
class MyListElem:
def __init__(self, item, link_from = None, link_to = None):
# Set data, link from previous and to next if specified.
self._item = item
self._next = link_to
if link_from is not None:
link_from.change_link(self)
def change_link(self, item):
self._next = item
The element class has two methods, the first creating an element with links as needed. At the moment (see MyList.add() below), the to link is always None as we only append to the list.
Similarly, the from link is either None or the current tail, depending on whether we're adding the first or subsequent elements to the list.
These parameters are mostly here to cater for the possibility of later being able to insert at arbitrary places in the list.
Next is the iterator class, also part of the list class:
# Iterator over the list.
class MyListIter:
def __init__(self, head):
# Start at the head.
self._curr = head
def __iter__(self):
# To iterate over the iterator rather than collection.
return self
def __next__(self):
# Check more left, advance to next and return current.
if self._curr is None:
raise StopIteration
ret_val = self._curr._item
self._curr = self._curr._next
return ret_val
This is relatively simple, the initialiser just sets us up so that the first call will return the head. The __iter__ call allows you to retrieve an iterator from the collection and then iterate over that, rather than iterating directly over the collection. The difference being:
for iter in object: # iterate over object
pass
iter = object.__iter__() # iterate over iterator
for iter2 in iter:
pass
See here for more details on why this may be necessary.
The __next__ call is the "meat" of the iterator. It raises an exception if the iterator is finished. Otherwise it returns the current value, after advancing to the next.
And then the list class itself, a very simple one that only allows appending to the end, no deleting, and an iterator to process it:
# The list itself.
def __init__(self):
# Empty list to start with.
self._head = None
self._tail = None
def add(self, val):
# Append to the end of the list.
if self._head is None:
self._head = self.MyListElem(val)
self._tail = self._head
else:
self._tail = self.MyListElem(val, self._tail)
def __iter__(self):
return self.MyListIter(self._head)
It's really that easy (well, relatively easy). The following test code shows it in action:
x = MyList()
x.add(12345)
x.add(42)
x.add("Hello")
x.add([1, 2, 3])
for i in x:
print(i)
The output of that is, as expected:
12345
42
Hello
[1, 2, 3]

Fixing My Base 10 to Binary Converter

Right now, I have a base 10 to base 2 converter that works, however it always prints none at the end of every conversion.
base_two=0
def binary_recursion(base_ten):
global base_two
if base_ten==0:
print(base_two)
return
c=0
while base_ten//2**c>1:
c+=1
base_two+=10**c
if c==0:
print(base_two)
return
binary_recursion(base_ten-2**c)
I tried returning base_two as opposed to printing it, but that doesn't return a number, it also just returns None. Can anyone help me pinpoint my mistake?
def node(document_info, next_node):
return {'data': document_info, 'next': next_node}
def insert(head, new_document_info):
#insert new document into the linked list head
#returns the head of the modified list
if head is None:
return node(new_document_info, None)
if new_document_info[1] <= head['data'][1]:
return node(new_document_info, head)
head['next'] = insert(head['next'], new_document_info)
return head
Here's a slightly modified way of doing insertion sort, from my answer to you last question. You would start with head = None and then every time you add a print job do head = insert(head, document_info). Or after collecting all of your print jobs do something like
head = None
for document_info in list_queue:
head = insert(head, document_info)
You are not adding new element into queue. Assuming list_queue is a queue.
Queue has put function to add a new element into it.
def make_job():
temp_list=[]
list_queue = Queue()
for line in print_list:
if line[:6]=='submit': #If the command is submit, then the file must be placed in its
a=line.split() #correct spot in the linked list
del(a[0])
list_queue.put(a)#Contains file id, and the time required to print
temp_list.append(list_queue)
organize(list_queue) #Places the file in its correct spot in the linked list
else:
break
The Python queue module has a class called PriorityQueue that does exactly what you're looking for. For your situation, using it would look something like this:
class Job(object):
def __init__(self, name, print_time):
self.name = name
self.print_time = print_time
def __lt__(self, other):
return self.print_time < other.print_time
import queue as _queue # Need to rename the module so it doesn't conflict with your 'queue' function
my_queue = _queue.PriorityQueue()
def make_job():
for line in print_list:
if line[:6]=='submit':
a=line.split()
del(a[0])
new_job=queue(a) # queue(a) now returns a Job, e.g. Job('101', 40), instead of a 2-element list
my_queue.put(new_job)
else:
break
Once my_queue has been constructed, then repeated calls to my_queue.get() will return the Jobs ordered by print_time.
If you want to be able to inspect the contents of the queue without removing elements (get removes the element it returns), you could append the Jobs to a list and call list_queue.sort() after every insertion. If this is a performance concern, you could find the right spot in the list yourself and call list_queue.insert(i, a). Deferring to Python's list.sort has some advantages, though; namely, it's stable.
Lastly, if you don't want to define a new class, you could use sorted or list.sort with a custom sorting function. This takes the place of the __lt__ member I defined for Job.
new_job=queue(a) # queue(a) is your original function, which returns 2-element lists like ['101', 40]
list_queue.append(new_job)
list_queue.sort(key=lambda a,b: return a[1]<b[1])

Understanding control flow in traversing through list

Here I have a class that contructs a node and a function that prints out the node in reverse order:
class LLNode(object):
def __init__(self, data):
'''(LLNode, object) -> NoneType
Create a new node to hold data
'''
self.data = data
self.link = None
def __str__(self):
return str(self.data)
def reverse_list(L):
if L is None: return
head = L
tail = head.link
reverse_list(tail)
print(head, end=' ')
list1 = LLNode(1)
list1.link = LLNode(2)
print(reverse_list(list1))
What I don't understand is when the print statement runs, since reverse_list(tail) is placed before it, to me it looks like it is ignored. What I find is if I switch those two lines the program will print the linked-list in-order, which makes sense to me. How does putting print after make it print in reverse? I'm not understanding the flow here.
Because by printing after the recursive call, it happens when control returns to the calling function, on the way back up the calls. Here is a simple example:
>>> def recur(x):
print("Going down ({0}).".format(x))
if not x:
print("Hit bottom")
print("Coming up ({0}).".format(x))
return None
recur(x-1)
print("Coming up ({0}).".format(x))
>>> recur(2)
Going down (2).
Going down (1).
Going down (0).
Hit bottom
Coming up (0).
Coming up (1).
Coming up (2).
Notice that what it prints is the head of the list. At each step, it "peels off" the first element of the list, stores it, then recursively calls itself on the rest of the list. On the last call, it will have only one element left. It will then print that element and return to the previous call, which will print the element it peeled off, which was the second-to-last element. That will then return to the previous call, which will print the element before that, and so on.
You can think of it as having a deck of cards, and the algorithm is, "Build a new stack by taking the top card off the deck and putting it down on top of the new stack. After you've done this with all the cards, go through the new stack from top to bottom and look at each card." As you go through the deck from top to bottom, you will put cards in the new stack from bottom to top, so you reverse the stack. Only after you've stacked all the cards into this reverse stack do you go back and look at them (which is like "printing" them), at which point you're looking at them in reverse order.

passing in self data in python

Can you please clarify how it is that self.add(x) below works the same way as self.data.append(x)?
That is, how does self.add(x) know to append to the list because we have not explicitly stated self.data.add(x)? When we state y.addtwice('cat'), 'cat' is added to 'self', not self.data.
class Bag:
def __init__(self):
self.data=[]
def add(self,x):
self.data.append(x)
return self.data
def addtwice(self,x):
self.add(x)
self.add(x)
return self.data
>>> y = Bag()
>>> y.add('dog')
['dog']
>>> y.addtwice('cat')
['dog', 'cat', 'cat']
Because addtwice calls methods which are defined on self, and because self.data is a "mutable type", addtwice's call to add will end up appending the value of self.data. add, in turn calls self.data.append
When calling a function in a computer program, you can think of the process as being a series of substitutions like this:
# -> means (substitution for)
# <= means "return"
y = Bag()
y.add('dog') ->
y.data.append(x) ->
#(machine code)
<= y.data
# at this point, at the command propmt, python will just print what was returned.
y.addtwice('cat')->
y.add('cat')->
y.data.append(x) ->
#(machine code)
<= y.data
#nothing cares about this return
y.add('cat')->
y.data.append(x) ->
#(machine code)
<= y.data
#nothing cares about this return either
<= y.data
# at this point, at the command propmt, python will just print what was returned.
self, itself, is never really appended in any of those cases though. self.data is.
self.add(x) calls the instance method add which in turn calls self.data.append(x)
When we state y.addtwice('cat'), 'cat' is added to 'self', not self.data
This is incorrect. cat is in fact added to self.data. Why would you think it was added to self?
y.add('dog') is the same as doing Bag.add(y, 'dog'). So add is really doing y.data.append('dog'), it's customary to use the name self instead.
y.addtwice('cat') is the same as doing Bag.addtwice(y, 'cat'). So addtwice is really doing y.add('cat') twice, which is the same as doing Bag.add(y, 'cat') twice. So addtwice is really doing y.data.append('cat') twice.
The self in each instance method is just an automatically added variable pointing to the instance it's called on, in this case y.
Let look at function add(self, x) from class Bag.
When that function is called, one of the parameter is self, which is the object itself, in this case, the same instance of Bag whose add function is called.
Therefore, in function add, calling self.data.append(x) is basically calling function append on data list of Bag, thus, adding the element x into the list.
Same thing for function addtwice. By calling function add twice, two elements are added into data list of Bag.
Both functions return the data list.
add(self, x) is just a function that you want to call.
append is a built in function that adds an element to the list.
so your add function basically uses append to add the element you want to the list and return the list you named data
self.addtwice will call self.add exactly two times and so will add the element twice.

How to walk up a linked-list using a list comprehension?

I've been trying to think of a way to traverse a hierarchical structure, like a linked list, using a list expression, but haven't come up with anything that seems to work.
Basically, I want to convert this code:
p = self.parent
names = []
while p:
names.append(p.name)
p = p.parent
print ".".join(names)
into a one-liner like:
print ".".join( [o.name for o in <???>] )
I'm not sure how to do the traversal in the ??? part, though, in a generic way (if its even possible). I have several structures with similar .parent type attributes, and don't want to have write a yielding function for each.
Edit:
I can't use the __iter__ methods of the object itself because its already used for iterating over the values contained within the object itself. Most other answers, except for liori's, hardcode the attribute name, which is what I want to avoid.
Here's my adaptation based upon liori's answer:
import operator
def walk(attr, start):
if callable(attr):
getter = attr
else:
getter = operator.attrgetter(attr)
o = getter(start)
while o:
yield o
o = getter(o)
The closest thing I can think of is to create a parent generator:
# Generate a node's parents, heading towards ancestors
def gen_parents(node):
node = node.parent
while node:
yield node
node = node.parent
# Now you can do this
parents = [x.name for x in gen_parents(node)]
print '.'.join(parents)
If you want your solution to be general, use a general techique. This is a fixed-point like generator:
def fixedpoint(f, start, stop):
while start != stop:
yield start
start = f(start)
It will return a generator yielding start, f(start), f(f(start)), f(f(f(start))), ..., as long as neither of these values are equal to stop.
Usage:
print ".".join(x.name for x in fixedpoint(lambda p:p.parent, self, None))
My personal helpers library has similar fixedpoint-like function for years... it is pretty useful for quick hacks.
List comprehension works with objects that are iterators (have the next() method). You need to define an iterator for your structure in order to be able to iterate it this way.
Your LinkedList needs to be iterable for it to work properly.
Here's a good resource on it. (PDF warning) It is very in depth on both iterators and generators.
Once you do that, you'll be able to just do this:
print ".".join( [o.name for o in self] )

Categories

Resources