Because stack allows to either push or pop, it is suitable to redo actions by just simply popping the latest action by the user. I have a stack class where:
class Node:
def __init__(self,item,the_next = None):
self.item = item
self.next = the_next
def __str__(self):
return str(self.item)
class LinkedStack:
def __init__(self):
self.top = None
self.count = 0
def __len__(self):
return self.count
def is_empty(self):
return self.count == 0
def isFull(self):
return False
def reset(self):
self.top = None
self.count = 0
def __str__(self):
current = self.top
ans = ""
while not (current is None):
ans += str(current)
ans += '\n'
current = current.next
return ans
def _get_node(self,index):
if 0<= index< len(self):
current = self.top
while index>0:
current = current.next
index -=1
return current
def pop(self):
if self.is_empty():
raise StopIteration("Stack is empty")
output = self.top.item
self.top = self.top.next
self.count -=1
return output
def push(self,item):
newNode = Node(item)
newNode.next = self.top
self.top = newNode
self.count +=1
if __name__ == "__main__":
L = LinkedStack()
and in another file, i import the stack from above and try to implement the undo action.
from Stack import LinkedStack
class Editor:
def __init__(self):
self.count = 0
self._list = LinkedList()
self._stack = LinkedStack()
def command(self,userCommand):
userCommand = userCommand.split(' ')
try:
if userCommand[0] == 'insert':
position = int(userCommand[1])
if len(userCommand) ==1:
raise Exception('no num is given')
textInput = input("Enter your text:")
self._stack.push(self.insertText(position,textInput)) #I'm thinking of adding the action into the stack by pushing it.
print(self._list)
pass
except Exception:
print('?')
if userCommand[0] == 'undo': #here if they choose to undo, by right i just pop the last action from the stack
self._stack.pop()
if __name__ == '__main__':
myCommand = Editor()
while True:
command = input('Enter an option:')
if command.lower() == 'quit':
break
else:
myCommand.command(command)
because I'm merely undoing actions, i thought of adding the command actions into a stack. if you take a look at the insert command above, where i added a comment, am i doing it correctly? Because I'm running out of ideas.
By the way, the insertText is a function which is working and I'm not planning to paste it here as it's getting lengthy. LinkedList() is just a linked list class i imported from another file as well.
The 'undo' doesn't seemed to revert the state. For example, if my LinkedList() contains:
1
2
3
4
None
and if i use the insert function to insert another number, 7 at index 1
1
7
2
3
4
None
and if i undo the action, I'm supposed to have:
1
2
3
4
None
Related
How can we get the previous and next item of a list in python? My code isn't working as it was supposed to. It always returns me 0th index of list. I dont want to use loop in this method.
Here's my code:
def provide_activetab_index(self,index):
if index > 0:
return index -1
if index < len(self.activetabs) - 1:
return index + 1
When i call this method it returns 0 when the self.current is 0.
def next(self):
index = self.provide_activetab_index(self.current+1)
self.display(self.frames[index])
def previous(self):
index = self.provide_activetab_index(self.current-1)
self.display(self.frames[index])
def next(self):
index = self.provide_activetab_index(self.current,1)
self.display(self.frames[index])
def previous(self):
index = self.provide_activetab_index(self.current,-1)
self.display(self.frames[index])
def provide_activetab_index(self,index,new):
if (index >= 0 and new == 1 and index < len(self.activetabs)-1) or (new == -1 and index > 0 and index < len(self.activetabs)):
return index + new
return index
EDIT
def provide_activetab_index(self,index,new):
l = len(self.activetabs)-1
if index >= l and new == 1:
return 0 # Return fist element if no last element
if index <= 0 and new == -1:
return l # Return last element if no previous element
else:
return index + new
To update self.current everytime
def next(self):
self.current = self.provide_activetab_index(self.current,1)
self.display(self.frames[self.current])
def previous(self):
self.current = self.provide_activetab_index(self.current,-1)
self.display(self.frames[self.current])
Hi i couldn't understand what you want exactly because there are few inputs that i don't know like self.current or self.activetabs so it is hard to modify your algorithm but there is data structure called "doubly_linked_list" you can implement that easily and than go to next or prev item with itemname.next or itemname.prev.Here is code
class Node:
def __init__(self, data, next_n=None, prev_n=None):
self.data = data
self.next = next_n
self.prev = prev_n
class Doubly_linked_list:
def __init__(self):
self.size = 0
self.root = None # points last member added
self.last = None # points first member added first member added is accepted as last member end next is None
def add(self, data):
if self.size == 0:
new_node = Node(data)
self.root = new_node
self.last = new_node
else:
new_node = Node(data)
new_node.next = self.root
self.root.prev = new_node
self.root = new_node
self.size += 1
def remove(self, data):
this_node = self.root
while this_node is not None:
if this_node.data == data:
if this_node.next is not None:
if this_node.prev is not None:
this_node.prev.next = this_node.next
this_node.next.prev = this_node.prev
else:
this_node.next.prev = None
self.root = this_node.next
else:
this_node.prev.next = None
self.last = this_node.prev
self.size -= 1
return True
else:
this_node = this_node.next
return False
def find_all(self, data):
this_node = self.root
while this_node is not None:
if this_node.data == data:
return data
elif this_node.next is None:
return False
else:
this_node = this_node.next
def print_all(self):
if self.root is None:
return None
this_node = self.root
print(this_node, end="-->")
while this_node.next != self.root:
this_node = this_node.next
print(this_node, end="-->")
print()
if you insist on finding nodes with indexes you can create a list object inside doubly_linked_list class inside init function self.list = [] and add all the nodes also to self.list and reach them by indexes.
With your code
def provide_activetab_index(self,index):
if index > 0:
return index -1
if index < len(self.activetabs) - 1:
return index + 1
when you pass index greater that 0 it will always return index-1.
As you mentioned self.current is 0 and you call it with
def next(self):
index = self.provide_activetab_index(self.current+1)
self.display(self.frames[index])
you actually calling
index = self.provide_activetab_index(1)
so this returns you 1-1 = 0
Assigned to design a linked list class from scratch using a generator to iterate through the list, but I've had a problem debugging this issue:
class LinkedList:
def __init__(self, data = None):
self.node = Node(data)
self.first = self.node
self.last = self.node
self.n = 1
def append(self, data = None):
new = Node(data)
self.last.next = new
self.last = new
self.n += 1
def __iter__(self):
self.index = self.first
return self.generator()
def generator(self):
for i in range(0, self.n):
yield self.index
self.index = self.index.next
One of the tests that the current generator passes is:
for n in a:
print n
# which should and does output
0
1
2
However, it fails to output the proper values in this case
for n in a:
if n == 2:
break
else:
print n
# Outputs 0 1 2, instead of:
0
1
I think my understanding of generators is lacking, and would love any help you guys have to offer!
Your shouldn't use n == 2 as the break-condition.
Try this:
# Assume your defined class `Node.py` like this:
class Node:
def __init__(self, data=None):
self.val = data
self.next = None
# I didn't modify your `LinkedList.py`
class LinkedList:
def __init__(self, data=None):
self.node = Node(data)
self.first = self.node
self.last = self.node
self.n = 1
def append(self, data=None):
new = Node(data)
self.last.next = new
self.last = new
self.n += 1
def __iter__(self):
self.index = self.first
return self.generator()
def generator(self):
for i in range(0, self.n):
yield self.index
self.index = self.index.next
if __name__ == '__main__':
ass = LinkedList(0)
ass.append(1)
ass.append(2)
ass.append(3)
for n in ass:
if n.val == 2: # Notice here
break
else:
print(n.val) # And here
I am aware that there is another post asking about simulated printers but I didn't find any actual answers to my own question there.
class LinkedQueue :
class _Node :
__slots__ = '_element', '_next'
def __init__(self, element, next = None):
self._element = element
self._next = next
def __init__(self) :
self._head = None
self._tail = None
self._size = 0
def __len__(self) :
return self._size
def is_empty(self) :
return self._size == 0
def first(self) :
if self.is_empty() :
raise Empty('Queue is empty')
return self._head._element
def dequeue(self) :
if self.is_empty():
raise Empty('Queue is empty')
answer = self._head._element
self._head = self._head._next
self._size -= 1
if self.is_empty() :
self._tail = None
return answer
def enqueue(self, e) :
newest = self._Node(e,None)
if self.is_empty() :
self._head = newest
else :
self._tail._next = newest
self._tail = newest
self._size += 1
class Printer:
def __init__(self, name, job_queue):
self._name = name
self._job_queue
self._current_job = None
class Empty(Exception) :
pass
def main():
p_jobs = LinkedQueue()
red = Printer("Red", p_jobs) # Creates Printer Red
green = Printer("Green", p_jobs) # Creates Printer Green
print("\nOptions:\n 1. Add Job \n 2. Print Pages \n 3. Status \
\n 4. Quit")
i = 0
while True:
n = str(input("\nChoice (Type the number): "))
if n == '1': # Add Job
i += 1
p = int(input("\nHow many pages? "))
j = p_jobs.job_list(i,p,next)
p_jobs.enqueue(j)
if n == '2': # Print Job
print()
p_jobs.dequeue()
i -= 1
if n == '3': # Status
print()
if n == '4': # Quit
print("\nGoodbye!")
break
This is the provided code for us. We are supposed to simulate two printers that print out pages from jobs using LinkedQueue and Node.
I have the main function barebones w/c consists of 4 options:
Add Job, Print Jobs, Status, and Quit
I have trouble understanding how to use (refer) to the enqueue and dequeue methods. Can somebody break down each part of this program so I can at least understand where to start. I also would appreciate any hints that tell me where to go from here. Thank you.
EDIT: I added my main function w/c is basically just a UI
While this is by no means a complete answer, it shows how to print out what's currently in a LinkedQueue instance.
First, add the following method to the class. It will allow the contents to be iterated.
class LinkedQueue:
def __iter__(self):
if self.is_empty():
return None # No jobs in print queue.
cur = self._head
while cur:
yield cur._element
cur = cur._next
Here's something demonstrating how to use it:
def test():
q = LinkedQueue() # Create a queue.
# Add some jobs to the LinkedQueue.
for j in range(3):
pages = randint(1, 10)
q.enqueue(('job #{}'.format(j), pages))
# Show what's currently in the LinkedQueue.
for v in q:
print(v)
# Modify the LinkedQueue and then show what's left in it.
j = q.dequeue()
print('\nafter removing one job')
for v in q:
print(v)
I am working on a doubly linked list and I can't get my remove function to work correctly. I want to return the value that it is being removed. I have tried various times, with no success. An extra pair of eye would be appreciated.
class DoublyLinked_List:
class __Node:
def __init__(self, val):
self.val = val
self.next = None
self.prev = None
def __init__(self):
self.__header = self.__Node(None)
self.__trailer = self.__Node(None)
self.__header.next = self.__trailer
self.__trailer.prev = self.__header
self.__size = 0
def __len__(self):
return self.__size
def remove_element_at(self, index):
if index > self.__size or index < 0 or index == self.__size:
raise IndexError
current = self.__header.next
if index == 0:
self.__header.next = self.__header.next.next
else:
for i in range(0, index-1):
current = current.next
current.next = current.next.next
self.__size -= 1
return current.val
I need some help in writing a python program that will implement a circular queue data structure (array-backed). I've completed a few of the methods already but I'm a bit stumped when it comes to adding and taking things away from the queue, as well as checking the values within it. I believe this is of the first-in-first-out structure. Here's what I have for the body so far
class Queue:
''' Constructor '''
def __init__(self, limit):
self.limit = limit
self.data = [None] * limit
self.queue = []
self.head = -1
self.tail = -1
self.count = 0
def dequeue(self):
if self.count == 0:
raise RuntimeError
else:
self.head = 0
x = self.queue.pop(0)
if self.head == self.tail:
self.head = -1
self.tail = -1
else:
self.tail -= 1
self.count -= 1
#self.head += 1
return x
def enqueue(self, item):
if self.count == self.limit:
raise RuntimeError
else:
self.count += 1
self.queue.append(item)
self.tail += 1
def __str__(self):
return " ".join([str(v) for v in self.queue])
def resize(self, new_limit):
new_q = [None]*self.limit
old_q = self.queue
for i in range(len(old_q)):
new_q[i] = old_q[i]
self.limit = new_limit
self.queue = new_q
def empty(self):
return 0 == self.count
def iter(self):
listt = []
for v in self.queue:
listt.append(v)
return listt
What I 've written thus far makes the most sense to me but if I were to test this with the following code block I'd get an error saying 10 != 4. This code will fail the 9th line of the test, tc.assertEqual(q.data.count(None), 4) I'm unsure why my code is producing the value 10 at this time. What would allow for this class to pass the given test?
from unittest import TestCase
tc = TestCase()
q = Queue(10)
for i in range(6):
q.enqueue(i)
tc.assertEqual(q.data.count(None), 4)
for i in range(5):
q.dequeue()
tc.assertFalse(q.empty())
tc.assertEqual(q.data.count(None), 9)
tc.assertEqual(q.head, q.tail)
tc.assertEqual(q.head, 5)
for i in range(9):
q.enqueue(i)
with tc.assertRaises(RuntimeError):
q.enqueue(10)
for x, y in zip(q, [5] + list(range(9))):
tc.assertEqual(x, y)
I'm pretty sure that all the code using self.queue is wrong. That attribute isn't needed at all. The whole point of the data attribute is to use it to store the values. Use the indexes head and tail to figure out where in data to put things (and where to take them from):
class Queue:
''' Constructor '''
def __init__(self, limit):
self.limit = limit
self.data = [None] * limit
self.head = 0
self.tail = -1
self.count = 0
def dequeue(self):
if self.count == 0:
raise RuntimeError
else:
x = self.data[self.head]
self.head = (self.head + 1) % self.limit
self.count -= 1
return x
def enqueue(self, item):
if self.count == self.limit:
raise RuntimeError
else:
self.count += 1
self.tail = (self.tail + 1) % self.limit
self.data[self.tail] = item
def __str__(self):
return " ".join([str(v) for v in self]) # use __iter__
def resize(self, new_limit):
if new_limit < self.count:
raise RuntimeError
new_data = [None]*new_limit
for i, item in enumerate(self):
new_data[i] = item
self.data = new_data
self.head = 0
self.tail = self.count - 1
def empty(self):
return 0 == self.count
def __bool__(self): # this is better than empty()
return self.count != 0
def __iter__(self): # renamed from iter so you can use it in a for loop
for i in range(self.count):
return self.data[(self.head + i) % self.limit]
You should probably also have a __len__ method.
I'd get an error stating that the Queue class doesn't have a data attribute
I don't have the error you mention when running your test on your code.
If for some reasons you don't want to use built-in collections.deque module, here is an example of how you can implement your own circular buffer:
"""
Example of circular buffer using regular list
"""
class CircularBuffer:
def __init__(self, size):
self.buffer = [None] * size
self.size = size
self.count = 0
self.tail = 0
self.head = 0
#property
def is_empty(self):
return self.count == 0
#property
def is_full(self):
return self.count == self.size
def __len__(self):
return self.count
def add(self, value):
# if buffer is full overwrite the value
if self.is_full:
self.tail = (self.tail + 1) % self.size
else:
self.count += 1
self.buffer[self.head] = value
self.head = (self.head + 1) % self.size
def remove(self):
if self.count == 0:
raise Exception("Circular Buffer is empty")
value = self.buffer[self.tail]
self.tail = (self.tail + 1) % self.size
self.count -= 1
return value
def __iter__(self):
index = self.tail
counter = self.count
while counter > 0:
yield self.buffer[index]
index = (index + 1) % self.size
counter -= 1
def __repr__(self):
return "[]" if self.is_empty else "[" + ",".join(str(i) for i in self) + "]"