Understanding control flow in traversing through list - python

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.

Related

Printing linked-list in python

In my task first I need to make single linked-list from array.
My code:
class Node:
def __init__(self,data):
self.data = data
self.next = next
class Lista:
def __init__(self, lista=None)
self.head = None
def ispis(self):
printval = self.head
while printval .next is not None:
print(printval.next.data)
printval = printval.next
if __name__ == '__main__'
L = Lista ([2, "python", 3, "bill", 4, "java"])
ispis(L)
With function ispis I need to print elements of linked-list. But it says name "ispis" is not defined. Cannot change ispis(L) !
EDIT: removed next from and ispis(self) is moved outside Lista class
while printvla.next is not None:
EDIT2:
It shows that L is empty so thats why it won't print anything. Should I add elements to class Node ?
ispis is a method in a class. But you are calling the function as if it is a normal function outside the class.
Atleast you have created the object correctly. Below would be the correct way of calling the method inside the class.
L.ispis()
This question sounds suspiciously like a homework assignment. If the instructor is trying to teach you how to create linked lists, you need to go back to what you need to do:
A node when set up for the first time only needs the data. Typically the next pointer/value would be set to None (meaning no next member).
Your __init__ method for your Lista class needs to do something with its argument.
I believe if you need to use your ispls function to operate on a class, then the function probably isn't supposed to be a member of Lista.
I think your ispls loop shouldn't be testing its .next member. This would fail if you had a None to begin with. You should be testing the current instance rather than its next. That way, when you move on to the next node, if it's None, it gets out of the loop.
Be careful with the keyword next. I would avoid using it as a class attribute. Also the literal next would just give you the built-in command.
At the bare minimum, you would want to iterate over the lista argument in __init__, creating a Node for each one, saving the previous node for the next operation.
if lista is None:
self.head = None
return
prev = None
for data in lista:
node = Node(data)
if prev is None:
self.head = node
else:
prev.next = node
prev = node
But again, I believe that is what the instructor wanted you to figure out. Hope this helped.
--B

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])

Unsure of how to use attributes and methods in python

I am currently working on an assignment where in a particular question I have to take a list of playing cards and, using a class, figure out if it is a Royal Flush.
The lecturer provided a 'skeleton' of code that I have to build the rest around without changing the parts he wrote.
#Lecturer created...
class PokerHand(Hand):
def __init__(self, cards = list()):
Hand.__init__(self, cards)
self.handRank = 0
self.hand = "High Card"
#I have so far added this part...
total_value = 0
val_card_b4 = 0
for card in self.cards:
if Card.getValue(card) > val_card_b4:
total_value += Card.getValue(card)
val_card_b4 = Card.getValue(card)
checkRoyalFlush()
#...to here. However it throws an error that checkRoyalFlush isn't defined.
#The lecturer then had what is below already added.
def checkHand(self):
if self.checkRoyalFlush():
self.handRank = 9
self.hand = "Royal Flush"
print("Test")
I have already created a Card class in an earlier question that allows me to create a card object get the value of the card (A=11, 2-10 equal face value etc.)
My problem is that, once I have checked the cards, I don't know how to 'activate' the if self.checkRoyalFlush(): statement in the checkHand Method.
The code I have to get running is:
h1 = PokerHand([Card('hearts', '10'), Card('clubs', '10'),Card('hearts', '2'),Card('hearts', '3'),Card('spades', 'J')])
h1.show()
print(h1.checkHand())
I would like to understand how to get the if statement working, as I have spent a lond time researching and can't figure it out. I am only a beginner in python and new to the Object Oriented side of it.
Edit: I also don't know how to define 'checkRoyalFlush' without it getting more errors
An if statement such as if self.checkRoyalFlush(): requires a boolean data type as a result, i.e. True or False. Your method needs to return either one of those values:
#Lecturer created...
class PokerHand(Hand):
def __init__(self, cards = list()):
# etc...
def checkHand(self):
# etc...
# add your new method below the methods that already exist
def checkRoyalFlush(self):
# paste your code to check if it is a royal flush here
# if it is a royal flush, then:
return True
# if it is NOT a royal flush, then:
return False
Also you need to refer to your method as self.checkRoyalFlush() as it is a part of the class PokerHand. You aren't doing that in checkHand() method.
It looks like your lecturer want method called checkRoyalFlush() which I'm assuming will return true if your hand is a royal flush or false if it isn't aren't.
Also note that I don't know how you set up your card class, and I don't know what you are calling the suit or value attribute. In the code below, I call .suit for the suit attribute and .value and the value attribute. Change it to whatever you made it as.
Consider code below:
class PokerHand:
def __init__(self, cards = list()):
#your init goes here as above
def checkHand(self):
#checkHand as above
def checkRoyalFlush(self):
check_suit = cards[0].suit #note I don't know what you are calling the suits and values in your hand,
values = ['A','K','Q','J','10'] #values we want to check against
for each_card in cards:
if not (each_card.typing == check_suit and each_card.value in values):
return False
values.remove(each_card.value) #once we found a value we want to remove it from the possible list
return True
The method checkRoyalFlush() will take one card's suit out of the cards list. Since a royal flush must have all the same suit it doesn't matter which card I choose. Here I choose the first card in the list.
Then I iterate through the cards list and check if NOT each of the card's typing is the same, and if each of the values are in the values list
if one card is does not match the requirement, it returns False.
We remove the value we checked so we can make sure it's 1 value and not duplicated values.
If the for loop checking is finished with out returning False, we know that it's a royal flush
Note this is not the most optimal way to do it, it's just one way that shows how it can be done rather clearly.

Reversing a Stack in 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())

Object Oriented Programming removing repeated items (Python)

I'm trying to remove an item from a sorted list. If the item is not in the list, then the list remains unchanged. If the item occurs multiple times, only one occurrence of the item is removed. Again, I'm not allowed to use build-in list functions, but for the time being, I'm just trying to get the code to just work!
class SortedList:
def __init__(self):
self.s_list = []
def insert(self, item):
self.s_list.append(item)
def remove(self, item):
finalSet=[]
for item in self.s_list:
if item not in finalSet:
finalSet.append(item)
return finalSet
def __str__(self):
return str(self.s_list)
Your remove function seems very confused.
def remove(self, item):
finalSet=[]
for item in self.s_list:
if item not in finalSet:
finalSet.append(item)
return finalSet
Why are you creating a new list, shouldn't you be modifying the existing list?
There are two different item in the function. One is a parameter to the function, the other is in the loop. The one in the loop replaces the parameter. Give them different names
You return with the list almost right away, you probably don't want to return until after the loop is completed. Your return statement is intended too far
Since you've confused two different variables by giving them the same name, I can't guess what you were actually trying to do inside the loop.
Other Question
Full page about topic

Categories

Resources