Taking elements from list and putting them in a stack with python - python

This is what i currently have and says that it is missing one argument when it tries to push i
this is the class that I have for this code
class ArrayStack:
def __init__(self):
self._data = []
def __len__(self):
return len(self._data)
def is_empty(self):
return len(self._data) == 0
def push(self, a):
self._data.append(a)
def top(self):
if self.is_empty():
raise Empty('Stack is empty')
return self._data[-1]
def pop(self):
if self.is_empty():
raise Empty('Stack is empty')
return self._data.pop()
def reverselist():
expression = input("Enter whatever: ")
stacks = ArrayStack
listofstuff = []
for item in expression:
listofstuff.append(item)
print(listofstuff)
for token in listofstuff:
i = str(token)
stacks.push(i)

You need an instance of ArrayStack, not the class itself, change for ArrayStack(), this calls the constructor of your class.
def reverselist():
expression = input("Enter whatever: ")
stacks = ArrayStack()
listofstuff = []
for item in expression:
listofstuff.append(item)
print(listofstuff)
for token in listofstuff:
i = str(token)
stacks.push(i)

Related

Queue implementation display function error

class Queue:
def __init__(self): '''initialization of function'''
self.items = []
def is_empty(self): '''Checking if queue is empty or not'''
return self.items == []
def enqueue(self, data): '''Adding value '''
self.items.append(data)
def dequeue(self): ''' Removing value'''
return self.items.pop(0)
def dis(self): '''Printing the stored item in queue'''
print(items)
After that initialization of Queue:
q = Queue()
while True:
print('enqueue <value>')
print('dequeue')
print('dis')
print('quit')
do = input('What would you like to do? ').split()
operation = do[0].strip().lower()
if operation == 'enqueue':
q.enqueue(int(do[1]))
elif operation == 'dequeue':
if q.is_empty():
print('Queue is empty.')
else:
print('Dequeued value: ', q.dequeue())
elif operation == 'dis':
q.dis()
elif operation == 'quit':
break
else:
print("Enter the correct operation")
I'm not able to display the items which are enqueued in the Queue. How could I use dis() method to display items in it?
Think you should print self.items (instead of items)
def dis(self): '''Printing the stored item in queue'''
print(self.items)
That'll output the list using standard formatting, not very pretty so you'll probably want to add some extra logic for pretty-printing.
If you want to restrict the queue size, you could do this by simply ignoring items past a certain limit. For this you'll need to implement a limit, along with logic for checking the limit. For example:
class Queue:
def __init__(self, size=8): '''initialization of function'''
self.items = []
self.size = size
def is_empty(self): '''Checking if queue is empty or not'''
return self.items == []
def enqueue(self, data): '''Adding value '''
if len(self.items) < self.size:
self.items.append(data)
else:
pass # behavior when queue is already full
def dequeue(self): ''' Removing value'''
return self.items.pop(0)
def dis(self): '''Printing the stored item in queue'''
print(items)
class Queue:
items=[]
size=5
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def enqueue(self, data):
self.items.append(data)
def dequeue(self):
return self.items.pop(0)
def dis(self):
print(self.items)
def is_full(self):
if (len(self.zitems)>5):
print("Queue is full")
else:
print("Not full")
Inizialize the items=[] and in dis method add self.items.Also, you could check if the size of the queue is full or not

Recursive Alternative/Merge Linked List Function with Multiple Linked List as Arguments?

I'm having trouble working with recursive linked list function with multiple linked list arguments.
So far I have came up with below, with a single linked list and works fine.
def recursive_ll(ll):
if ll == None:
return None
elif ll.next == None:
return LN(ll.value)
else:
return_ll = LN(ll.value, recursive_ll(ll.next))
if return_ll.value == return_ll.next.value:
return_ll = return_ll.next
return return_ll
Result will be:
ll = list_to_ll(['x','g','f','n'])
print(str_ll(recursive_ll(ll)))
x->g->f->n->None
But I am really confused with how I can create recursive linked list function with multiple linked lists as arguments.
For example, def recursive_ll(ll): will be def recursive_ll(ll, ll2):
And returned result would be
ll = recursive_ll(['a','x','b','e'])
ll2 = recursive_ll(['d','f','m'])
a->d->x->f->b->m->e->None
Again, desired result below, combined from two linked list:
a->d->x->f->b->m->e->None
Any help/suggestions will be much appreciated!
You should use classes instead of simple functions as helpers. And accept any iterable as the source for a linked list. If you implement iterators on the linked list class, that would allow trivial conversion between any iterable and a linked list.
The linked list class could be:
class LL:
class iter:
def __init__(self, ll):
self.cur = ll.front
def __iter__(self):
return self
def __next__(self):
if self.cur is None:
raise StopIteration()
val = self.cur.value
self.cur = self.cur.next
return val
def __init__(self, l):
self.front = last = None
for v in l:
ln = LN(v)
if last is None:
self.front = ln
else:
last.next = ln
last = ln
def __str__(self):
answer = ''
for val in self.iter_elt():
answer += str(val) + '->'
return answer + 'None'
def __repr__(self):
return str(self.__class__) + ':' + str(self)
def __iter__(self):
return LL.iter(self)
This immediately allows:
>>> print(LL('abcd'))
a->b->c->d->None
>>> list(LL('abcd'))
['a', 'b', 'c', 'd']
Once this is done, you can declare a Recursive Linked List as a subclass of a Linked List which allows to extract the elements in a merge order if it contains Linked Lists.
You should first add a new method iter_elt in LL class that just calls iter and use that in __str__ to ease the subclassing:
class LL:
...
def __str__(self):
answer = ''
for val in self.iter_elt():
answer += str(val) + '->'
return answer + 'None'
...
def iter_elt(self):
return self.__iter__()
Because now, it is enough to override iter_elt in RLL, and build an iterator that will scan its sublists repeatedly calling iter_elt on them if possible else iter, until all are exhausted. Code could be:
class RLL(LL):
class iter:
def __init__(self, rll):
self.iters = LL(i.iter_elt() if hasattr(i, 'iter_elt') else iter(i)
for i in rll)
self.cur = self.iters.front
self.prev = None
def __iter__(self):
return self
def __next__(self):
try:
elt = next(self.cur.value)
self.prev = self.cur
self.cur = self.cur.next
if self.cur is None:
self.cur = self.iters.front
self.prev = None
except StopIteration:
self.cur = self.cur.next
if self.cur is None:
if self.prev is None:
raise
self.cur = self.iters.front
self.prev = None
else:
if self.prev is None:
self.iters.front = self.cur
else:
self.prev.next = self.cur
elt = self.__next__()
return elt
def iter_elt(self):
return RLL.iter(self)
I totally agree with #Serge Ballesta that you should create a LinkedList class to do this, here's how it could be done the procedural way you're doing things.
Also note that it's not done recursively—but rather "pythonically".
from itertools import chain, zip_longest
class LN:
def __init__(self, value, next=None):
self.value = value
self.next = next
def list_to_ll(l):
if l == []:
return None
front = rear = LN(l[0])
for v in l[1:]:
rear.next = LN(v)
rear = rear.next
return front
def iterate(ll):
while ll is not None:
yield ll.value
ll = ll.next
def str_ll(ll):
return '->'.join(str(v) for v in iterate(ll)) + '->None'
def alternate(ll_1, ll_2):
_NULL = object()
chained = chain.from_iterable(zip_longest(iterate(ll_1), iterate(ll_2),
fillvalue=_NULL))
return list_to_ll(list(v for v in chained if v is not _NULL))
if __name__ == '__main__':
ll_1 = list_to_ll(['a','x','b','e'])
ll_2 = list_to_ll(['d','f','m'])
print(str_ll(alternate(ll_1, ll_2))) # -> a->d->x->f->b->m->e->None

Doubly-linked list in Python

It turned out to be an error as a time limit was exceeded,
but I've already raised the StopIteration...
I think I did something wrong for my iteration part, but it's really hard to find the error. The test output keeps running and even printed out the None value. How does it happen?
class LinkedListIterator:
def __init__(self, head):
self.__current = head.get_next()
def __iter__(self):
return self
def __next__(self):
if self.__current == None:
raise StopIteration
else:
item = self.__current.get_data()
self.__current = self.__current.get_next()
return item
These were the inputs I used to run the program:
my_list = LinkedListDLL()
my_list.add_to_head(1)
print("Contents:", end=" ")
for node in my_list:
print(node, end=" ")
print()
This code is meant to stop iteration when it reaches the head of the list.
if self.__current == None:
raise StopIteration
However, you represent the head with a NodeDLL object which is different from None.
You could keep a reference to the head and check against that instead:
class LinkedListIterator:
def __init__(self, head):
self._head = head
self._current = head.get_next()
def __iter__(self):
return self
def __next__(self):
if self._current is self._head:
raise StopIteration
else:
item = self._current.get_data()
self._current = self._current.get_next()
return item
What you want to implement is the API of a MutableSequence with the implementation of a doubly-linked-list.
To do that in Python, you should rely on collections.abc which can guide you through the process of implementing all required methods.
By example, a linked-list is actually a class inheriting from MutableSequence.
from collections.abc import MutableSequence
class LinkedList(MutableSequence):
pass
ll = LinkedList()
On instantiation of a class which has some abstract methods not yet written, you will get a TypeError which will guide you through which methods need to be implemented.
TypeError: Can't instantiate abstract class LinkedList with abstract methods __delitem__, __getitem__, __len__, __setitem__, insert
In particular, note that a list or a linked-list is not an iterator, it is an iterable. What this means is the __iter__ method should not return self and rely on __next__, it should instead return a brand new iterator on the content of the linked-list.
In other words, you can iterate only once through an iterator and multiple times through and iterable.
Full implementation
It turns out I have a full implementation of a doubly-linked-list implemented that way. You can have a look.
from collections.abc import MutableSequence
class LinkedList(MutableSequence):
class _Node:
def __init__(self, value, _next=None, _last=None):
self.value, self._next, self._last = value, _next, _last
def __str__(self):
return f'Node({self.value})'
def __init__(self, iterable=()):
self.start = None
self.last = None
empty = object()
iterable = iter(iterable)
first = next(iterable, empty)
if first is empty:
return
current = self._Node(first)
self.start, self.last = current, current
for value in iterable:
new_node = self._Node(value, _last=self.last)
self.last._next = new_node
self.last = new_node
def __len__(self):
if self.start is None:
return 0
else:
return sum(1 for _ in self)
def __iter_nodes(self):
current = self.start
while current is not None:
yield current
current = current._next
def __reversed_iter_nodes(self):
current = self.last
while current is not None:
yield current
current = current._last
def __iter__(self):
for node in self.__iter_nodes():
yield node.value
def __reversed__(self):
for node in self.__reversed_iter_nodes():
yield node.value
def __get_node(self, index):
if index >= 0:
for item in self.__iter_nodes():
if index == 0:
return item
index -= 1
else:
for item in self.__reversed_iter_nodes():
if index == 0:
return item
index += 1
raise IndexError
def __getitem__(self, index):
if index >= 0:
for item in self:
if index == 0:
return item.value
index -= 1
else:
for item in reversed(self):
if index == 0:
return item.value
index += 1
raise IndexError
def __setitem__(self, key, value):
self[key].value = value
def __delitem__(self, key):
node = self[key]
if node._last:
node._last._next = node._next
if node._next:
node._next._last = node._last
def insert(self, index, value):
if index > len(self):
self.last = self._Node(value, _last=self.last)
else:
where = self.__get_node(index)
_last = where._last
new_node = self._Node(value, _next=where, _last=_last)
if _last:
_last._next = new_node
else:
self.start = new_node
where._last = new_node
Example
ll = LinkedList(range(1, 5))
print(*ll)
print(*reversed(ll))
ll.insert(2, 'foo')
print(*ll)
Output
1 2 3 4
4 3 2 1
1 2 foo 3 4

Instance method is not working from an object while it works perefctly from its class

This is the most strange error that I got since I started to program with Python years ago.
First, theses are my classes (Sorry for the long code):
class Quran(Iterable):
def __init__(self):
self.sourats = []
def __iadd__(self, other):
# There is some code here
pass
def __getitem__(self, sourat_num):
if not (isinstance(sourat_num, int) or isinstance(sourat_num, slice)):
raise TypeError('Indexing Quran can be done only using ints or slices')
if isinstance(sourat_num, int):
sourat_num -= 1
else:
sourat_num = slice(sourat_num.start - 1, sourat_num.stop)
try:
return self.sourats[sourat_num]
except IndexError:
return None
def __len__(self):
return len(self.sourats)
# Other methods ...
class Sourat(Iterable):
sourats_titles = [ # 114 strs here
]
def __init__(self, number, quran):
if not isinstance(number, int):
raise TypeError('number must be int')
if not isinstance(quran, Quran):
raise TypeError('quran must be Quran')
self.num = number
self.ayats = []
self.quran = quran
def __int__(self):
return self.num
def __iadd__(self, other):
# Some code here
pass
def __getitem__(self, ayat_num):
if not (isinstance(ayat_num, int) or isinstance(ayat_num, slice)):
raise TypeError('Indexing Sourat can be done only using ints or slices')
if isinstance(ayat_num, int):
ayat_num -= 1
else:
ayat_num = slice(ayat_num.start-1, ayat_num.stop)
try:
return self.ayats[ayat_num]
except IndexError:
return None
def __len__(self):
return len(self.ayats)
def location(self):
return self.num
def previous(self):
p_num = self.num-1
if p_num < 1:
return None
return self.quran[p_num]
def next(self):
n_num = self.num+1
if n_num > len(self.quran):
return None
return self.quran[n_num]
# Other methods ...
class Word(Iterable):
def __init__(self, number, text, features, ayat):
if not isinstance(number, int):
raise TypeError('number must be int')
if not isinstance(text, str):
raise TypeError('text must be str')
if not (isinstance(features, dict) and features['type'] in ('PREFIX', 'STEM', 'SUFFIX')):
raise TypeError('features[type] must be one of PREFIX, STEM, SUFFIX')
if not isinstance(ayat, Ayat):
raise TypeError('ayat must be Ayat')
self.num = number
self.text = text
self.root = features.get('ROOT', None)
self.lem = features.get('LEM', None)
self.type = features['type']
self.next = None
self.previous = None
self.ayat = ayat
def __iadd__(self, other):
# Some code here
def __hash__(self):
# Some code here
pass
def previous(self):
p_num = self.num-1
if p_num < 1:
previous_ayat = self.ayat.previous()
if previous_ayat:
return previous_ayat[-1]
else:
return None
return self.ayat[p_num]
def next(self):
n_num = self.num+1
if n_num > len(self.ayat):
next_ayat = self.ayat.next()
if next_ayat:
return next_ayat[0]
else:
return None
return self.ayat[n_num]
# Other methods ...
And this is what I am have in the main code :
quran_last_14_sourats = parse_quranic_corpus('quranic-corpus-morphology-0.4-last-14-sourats.txt')
sourat = quran_last_14_sourats[2]
ayat = sourat[2]
word = ayat[1]
assert isinstance(ayat, Ayat)
assert isinstance(word, Word)
print(ayat.previous())
print(ayat)
print(ayat.next())
print(Word.next(word)) # This works !!!
print(word.next()) # This doesn't work !!!
My problem is in the next(self) and previous(self) in the class Word, everything else works perfectly.
When I try to use word.next() or word.previous(), it complains that NoneType is not callable. I tried to print(word.next) and it showed None, but this is not logical because these two methods are inside the class Word. This problem doesn't happen in classes Sourat and Ayat even that they have the same structure. And the most crazy thing is that Word.next(word) works without any problem !
Is this a bug in Python 3 ? (BTW I am using the latest version: 3.5.2)
Is this a bug in Python 3 ?
In a word, no.
Instance members and instance methods share the same namespace. Thus, your line in Word.__init__():
self.next = None
obliterates the reference to the method Word.next() inside the newly-allocated Word object.

How to use Iterator that traverses the doubly linked list and skips null nodes

Since the doubly linked list has two dummy nodes, one is the head and the other one is the tail. I can skip the dummy tail node by self.__current == None: raise StopIteration, but I don't know how to pass the dummy head nodes and continue traverse the following node.
class LinkedListDLL:
def __init__(self):
self.__head = NodeDLL(None)
self.__head.set_next(self.__head)
self.__head.set_prev(self.__head)
self.__count = 0
def size(self):
return self.__count;
def is_empty(self):
return self.__count == 0
def add_before(self, item, curr):
new_node = NodeDLL(item)
new_node.set_next(curr)
new_node.set_prev(curr.get_prev())
curr.set_prev(new_node)
new_node.get_prev().set_next(new_node)
self.__count += 1
def add_to_head(self, item):
self.add_before(item, self.__head.get_next())
def add_to_tail(self, item):
self.add_before(item, self.__head)
def remove_from_head(self):
self.remove(self.__head.get_next())
def remove_from_tail(self):
self.remove(self.__head.get_prev())
def remove(self, curr):
curr.get_prev().set_next(curr.get_next())
curr.get_next().set_prev(curr.get_prev())
self.__count -= 1
def __iter__(self):
return LinkedListIterator(self.__head)
class LinkedListIterator:
def __init__(self, head):
self.__current = head
def __next__(self):
if self.__current == None :
raise StopIteration
else:
item = self.__current.set_data.get_next()
self.__current = self.__current.get_next()
return item
You should refactor your code keeping in mind that NodeDLL(None) may not be the same as None. With that done:
def __next__(self):
if not self.__current.get_next():
raise StopIteration
#Skips first value in list, i.e. head
self.__current = self.__current.get_next()
return self.__current

Categories