Python: FIFO with limited depth - optimisation question and review - python

Again, I am new to python. I need a FIFO with a limited depth.
F.e the depth is 5000, so after 5000 and more added items the first one's should be deleted to keep its depth is 5000. Some times I need to read 'the first' one and sometimes read the 'last one'. If I read the first one then it should be removed.
# class
class DictionaryDeque:
from collections import OrderedDict
def __init__(self, dequeDict=10):
self._stack = OrderedDict()
self._range = dictRange
self.setRange(dictRange)
self._len = 0
def len(self):
self._len = len(self._stack)
return self._len
def getRange(self):
return self._range
def setRange(self, range):
self._range = range
# change the dict range if the dict has more items
self.do_pop()
def add(self, key, value):
self._stack[key] = value
self.len()
self.do_pop()
def stack(self):
if self._len > 0:
self.do_pop()
return self._stack
else:
return ""
def last(self):
self.do_pop()
if self._len > 0:
return list(self._stack)[-1]
else:
return list(self._stack)[0]
def first(self):
self.do_pop()
return list(self._stack)[0]
def do_pop(self):
while self.len() > self._range:
self._stack.popitem(last=False)
self.len()
# end of class
dequeDict = DictionaryDeque(30)
for i in range (0, 40):
now = str(datetime.datetime.now())
dequeDict.add(now, i)
dequeDict.setRange(10)
print(dequeDict.len())
print(dequeDict.last())
print(dequeDict.first())
print(dequeDict.stack())
I have to implement the 'first read and remove' and some more functions, but before I start with that, I would love to know if this the/a way to go, or should there be something better?
Is there a way to avoid the list part in
list(self._stack)[0]
?
BTW, what is a good name for this class? < class name changed
Thank you

Related

How can I overload the __repr__ method to display all items in a linked list Stack?

I've created my Node and Stack classes, but I can't figure out how I can display the repr in the Stack class in order to be able to print all items currently in the stack? I've been trying to concatenate the nodes but I'm not sure how since the Stack() doesn't allow iterating through the way a list does?
The stack works as it should, I just don't know how to display it's contents?
Here is my code:
class Stack:
class Node:
def __init__(self, elem, next):
self.elem = elem
self.next = next
def __repr__(self):
return str(self.elem)
def __init__(self):
self._stack = None
self._size = 0
def __repr__(self):
# *Not sure how to implement this properly*
s = ''
for i in range(self._size):
last = self._stack.elem
s += (str(last))+ ', '
self._stack.elem = self._stack.next
return
def push(self, elem):
if self._stack == None:
self._stack = self.Node(elem, None)
self._size += 1
else:
self._stack = self.Node(elem, self._stack)
self._size += 1
def pop(self):
if self._stack == None:
raise Exception ('This Stack is empty!')
else:
last = self._stack.elem
self._stack = self._stack.next
self._size -= 1
return last
def top(self):
return self._stack.elem
def isEmpty(self):
return self._size == 0
Example:
s= Stack()
s.push(4)
s.push(9)
s.push("joe")
s
joe, 9, 9,
Thank you in advance.
A way simpler implementation that avoids all the problems and pitfalls of your solution:
from typing import Iterable, Any
class Stack:
def __init__(self, xs: Iterable = None):
self._items = [] if xs is None else list(xs)
def push(self, elem: Any):
self._items.append(elem)
def pop(self) -> Any:
return self._items.pop()
def top(self) -> Any:
return self._items[-1]
def isEmpty(self) -> bool:
return not self._items
def __repr__(self) -> str:
typename = type(self).__name__
return f'{typename}({self._items})'
def __str__(self) -> str:
return ', '.join(str(x) for x in self._items)
s = Stack()
s.push(4)
s.push(9)
s.push("joe")
print(s)
print(repr(s))
But note that there's little use to a class like this over just using a list like a stack to begin with.
The output:
4, 9, joe
Stack([4, 9, 'joe'])
Note that this has the top element at the end, you could reverse it if you like of course.
If you insist on a working __repr__ for your specific implementation, using __repr__ as you intend in a non-standard way, something like this would work:
def __repr__(self):
p = self._stack
elems = []
while p is not None:
elems.append(p.elem)
p = p.next
return ', '.join(elems)
But note that there's several other issues with your implementation, other than this not being a correct __repr__, as previously pointed out here and in the comments. Your 'node' has a __repr__ which just returns its element value (which isn't a valid representation at all in most cases); you seem to be using __repr__ where you're really after __str__.
If this were an assignment in programming class, I'm not sure I'd award a passing grade, depending on what the aim was.

Max stack in python - 2 stacks solution

I am trying to build a max stack in python, I am not sure what I am doing wrong.
Here is the question>
Design a max stack data structure that supports the stack operations
and supports finding the stack's maximum element.
Implement the MaxStack class:
MaxStack() Initializes the stack object.
void push(int x) Pushes element x onto the stack.
int pop() Removes the element on top of the stack and returns it.
int top() Gets the element on the top of the stack without removing it.
int peekMax() Retrieves the maximum element in the stack without removing it.
int popMax() Retrieves the maximum element in the stack and removes it.
If there is more than one maximum element, only remove the top-most one.
class MaxStack:
def __init__(self):
self.stack = []
self.stack_max = []
def push(self, x: int) -> None:
self.stack.append(x)
if not self.stack_max or x > self.stack_max[-1][0]:
self.stack_max.append([x, 1])
elif x == self.stack_max[-1][0]:
self.stack_max[-1][1] += 1
else:
self.stack_max.append(self.stack_max[-1])
def pop(self) -> int:
if not self.stack_max or self.stack:
return
if self.stack_max[-1][0] == self.stack[-1]:
self.stack_max[-1][1] -= 1
if self.stack_max[-1][1] == 0:
del self.stack_max[-1]
return self.stack.pop()
def top(self) -> int:
return self.stack[-1]
def peekMax(self) -> int:
if self.stack_max:
return self.stack_max[-1][0]
def popMax(self) -> int:
if self.stack_max:
return self.stack_max.pop()[0]
Example code:
obj = MaxStack()
obj.push(6)
param_2 = obj.pop()
param_3 = obj.top()
param_4 = obj.peekMax()
param_5 = obj.popMax()
Input :
["MaxStack","push","push","push","top","popMax","top","peekMax","pop","top"] [[],[5],[1],[5],[],[],[],[],[],[]]
Output:
[null,null,null,null,5,5,5,5,None,5]
Expected:
[null,null,null,null,5,5,1,5,1,5]
Reference: Leetcode 716. Max Stack
class MaxStack:
def __init__(self,value):#taking some value to avoid empty obj
self.stack=[value]
self.max_=[value,0]
self.length=1
def push(self,value):
self.stack.append(value)
self.length+=1
if value>self.max_[0]:
self.max_[0],self.max_[1]=value,self.length-1
def pop(self):
if self.length==0:
return
elif self.stack[-1]==self.max_[0]:
self.popMax()
else:
self.stack.pop()
self.length-=1
def top(self):
print(self.stack[-1])
def peekMax(self):
print(self.max_[0])
def popMax(self):
if self.length==0 or self.max_[1]==-1:
return
self.stack.pop(self.max_[1])
self.length-=1
self.max_[0],self.max_[1]=-1,-1
for i in range(self.length):
if self.stack[i]>self.max_[0]:
self.max_[0],self.max_[1] = self.stack[i],i
Sorry for the improper indentations, I tried a lot to fix it. Anyways this should work and I wanted to try it out on leetcode but it needs a login. Let me know if there is any issue.
To me, it seems a little confusing to track the count in the tuple of the value, when you could just continue adding to the max stack and counting them from the list if you need that.
class MaxStack:
def __init__(self):
self.stack = []
self.maxes = []
def push(self, n):
self.stack.append(n)
if not self.maxes or n >= max(self.maxes):
self.maxes.append(n)
def pop(self):
if self.stack:
val = self.stack.pop()
if val in self.maxes:
self.maxes.remove(val)
def top(self):
if self.stack:
return self.stack[-1]
def peek_max(self):
if self.maxes:
return self.maxes[-1]
def pop_max(self):
if self.maxes:
return self.maxes.pop()
Then if you need the count of the number of each, just use count():
def max_count(self):
if self.maxes:
return self.maxes.count(max(self.maxes))

Python OOP Disjoint Set Performance

I built a disjoint-set data structure for use with Kruskal's MST algorithm. I need to load and then union a graph with 200k interconnected nodes and I think my data structure implementation is a bottleneck.
Do you have an suggestions for how to improve performance? I think my find method might be problematic.
class partition(object):
def __init__(self, element=None):
self.size = 0
if element == None:
self.contents = set()
self.representative = None
else:
self.contents = {element}
self.representative = element
self.size = 1
def find(self, element):
return element in self.contents
def add(self, partition):
self.contents = self.contents.union(partition)
self.size = len(self.contents)
def show(self):
return self.contents
def __repr__(self):
return str(self.contents)
class disjoint_set(object):
def __init__(self):
self.partitions_count = 0
self.forest = {}
def make_set(self, element):
if self.find(element) == False:
new_partition = partition(element)
self.forest[new_partition.representative] = new_partition
self.partitions_count += 1
def union(self, x, y):
if x != y:
if self.forest[x].size < self.forest[y].size:
self.forest[y].add(self.forest[x].show())
self.delete(x)
else:
self.forest[x].add(self.forest[y].show())
self.delete(y)
def find(self, element):
for partition in self.forest.keys():
if self.forest[partition].find(element):
return self.forest[partition].representative
return False
def delete(self, partition):
del self.forest[partition]
self.partitions_count -= 1
if __name__ == '__main__':
t = disjoint_set()
t.make_set(1)
t.make_set(2)
t.make_set(3)
print("Create 3 singleton partitions:")
print(t.partitions_count)
print(t.forest)
print("Union two into a single partition:")
t.union(1,2)
print(t.forest)
print(t.partitions_count)
EDIT:
After reading the comments and doing additional research I realized how poorly designed my original algorithm was. I started over from scratch and put this together. I put all the partitions into a single hash table and used path compression in the find(). How does this look and are there any glaring problems I should address?
class disjoint_set(object):
def __init__(self):
self.partitions_count = 0
self.size = {}
self.parent = {}
def make_set(self, element):
if self.find(element) == False:
self.parent[element] = element
self.size[element] = 1
self.partitions_count += 1
def union(self, x, y):
xParent = self.find(x)
yParent = self.find(y)
if xParent != yParent:
if self.size[xParent] < self.size[yParent]:
self.parent[xParent] = yParent
self.size[yParent] += self.size[xParent]
self.partitions_count -= 1
else:
self.parent[yParent] = xParent
self.size[xParent] += self.size[yParent]
self.partitions_count -= 1
def find(self, element):
if element in self.parent:
if element == self.parent[element]:
return element
root = self.parent[element]
while self.parent[root] != root:
root = self.find(self.parent[root])
self.parent[element] = root
return root
return False
if __name__ == '__main__':
t = disjoint_set()
t.make_set(1)
t.make_set(2)
t.make_set(3)
t.make_set(4)
t.make_set(5)
print("Create 5 singleton partitions")
print(t.partitions_count)
print("Union two singletons into a single partition")
t.union(1,2)
print("Union three singletones into a single partition")
t.union(3,4)
t.union(5,4)
print("Union a single partition")
t.union(2,4)
print("Parent List: %s" % t.parent)
print("Partition Count: %s" % t.partitions_count)
print("Parent of element 2: %s" % t.find(2))
print("Parent List: %s" % t.parent)
I guess your find implementation is not running effienctly, which it supposed to be.
Following changes may help.
class disjoint_set(object):
def __init__(self):
self.partitions_count = 0
self.forest = {}
self.parent = {}
def make_set(self, element):
if not self.find(element):
new_partition = partition(element)
self.parent[element] = element
self.forest[new_partition.representative] = new_partition
self.partitions_count += 1
def union(self, x, y):
if x != y:
if self.forest[x].size < self.forest[y].size:
self.forest[y].add(self.forest[x].show())
#Update parent details
self.parent[self.forest[x].representative] = self.forest[y].representative
self.delete(x)
else:
self.forest[x].add(self.forest[y].show())
#Update parent details
self.parent[self.forest[y].representative] = self.forest[x].representative
self.delete(y)
def find(self, element):
if self.parent[element] == element:
return element
else:
return find(element)
The code can be still optimized with path-compression to have disjoint_set.find to run in O(1). I guess O(log n) still is good for big numbers.
Another bottleneck could be your union function. Especially the add function implementation.
def add(self, partition):
self.contents = self.contents.union(partition)
Try using an update method of set (which is an inplace union). I think is causing lot of memory overhead for huge no.of nodes. Something like
self.contents.update(partition)
There is a nice discussion on set union and update functions here.
Hope it helps!

How to create new class instances dynamically at runtime in python?

I am trying to solve this problem:
Imagine a (literal) stack of plates. If the stack gets too high, it
might topple. There- fore, in real life, we would likely start a new
stack when the previous stack exceeds some threshold. Implement a data
structure SetOfStacks that mimics this. SetOf- Stacks should be
composed of several stacks, and should create a new stack once the
previous one exceeds capacity. SetOfStacks.push() and
SetOfStacks.pop() should behave identically to a single stack (that
is, pop() should return the same values as it would if there were just
a single stack). Bonus: Implement a function popAt(int index) which
performs a pop operation on a specific sub-stack.
So I wrote the code:
#!/bin/env python
from types import *
class Stack:
def __init__(self):
self.items = []
self.capacity = 3
self.stackscount = 0
def create(self):
id = self.stackscount + 1
id = str(id) + "_stack"
# How to create a new instance of Stack class at runtime ?
# the __init__ must be run too.
def push(self, item):
if self.size() <= self.capacity:
self.items.append(item)
else:
self.create()
def pop(self):
return self.items.pop()
def popAt(self):
pass
def peek(self):
return self.items[len(self.items)-1]
def size(self):
return len(self.items)
s = Stack()
s.push(10)
How do I create a new s type object dynamically at runtime? I searched on the internet and found that using new.instance or new.classobj is the solution but when I did so my new object did not seem to have items from __init__ function. In python3, type() seems to be the answer but the docs doesn't have any examples.
You've confused yourself by referring to a "type object". In Python that means the class itself, not its instances.
To create new Stack objects, simply do what you're already doing: call the Stack class. You can append them to a list:
stacks = [Stack() for _ in range(5)]
However, as jon points out, that won't solve your problem since you haven't defined the SetOfStacks class.
You could simply use a parent-child relation : when a Stack is full, it creates a child and delegate next pushes to it. It could lead to :
class Stack:
def __init__(self, parent = None, id=None):
self.stackscount = 0
self.capacity = 3
self.items = []
self.parent = parent
self.id = id
self.child = None
def create(self):
id = self.stackscount + 1
id = str(id) + "_stack"
return Stack(self, id)
def push(self, item):
if self.size() <= self.capacity:
self.items.append(item)
else:
if self.child is None:
self.child = self.create()
self.child.push(item)
def pop(self):
if self.child is not None:
item = self.child.pop()
if len(self.child.items) == 0:
self.child = None
else:
item = self.items.pop()
return item
def popAt(self):
pass
def peek(self):
if self.child is not None:
item = self.child.peek()
else:
item = self.items[len(self.items)-1]
return item
def size(self):
l = len(self.items)
if self.child is not None:
l += self.child.size()
return l
s = Stack()
s.push(10)
popAt is still to be implemented, but I tested it and it correctly creates new stacks when pushing and empties and removes them when popping.
The implementation of popAt will require some evolutions to current pop implementation, to allow removing an intermediate stack :
def pop(self):
if self.child is not None:
item = self.child.pop()
if len(self.child.items) == 0:
self.child = self.child.child
if self.child is not None:
self.child.parent = self
else:
item = self.items.pop()
return item
def popAt(self, stacknumber):
s = self
for i in range(stacknumber):
s = s.child
if s is None:
return None
if len(s.items) == 0:
return None
item = s.items.pop()
if len(s.items) == 0 and s.parent is not None:
s.parent.child = s.child
if s.child is not None:
s.child.parent = s.parent
return item
The type() function is indeed what you are looking for. Documentation can be found here: https://docs.python.org/2/library/functions.html#type
You can call it like this:
# Bases is a tuple of parent classes to inherit
bases = Stack,
# Dict contains extra properties for the class, for example if you want to add a class variable or function
dict_ = {}
# Construct the class
YourClass = type('YourClass', bases, dict_)
# Create an instance of the class
your_instance = YourClass()
It looks like you are just looking at instance creation though:
class Stack(object):
def create(self):
id = self.stackscount + 1
id = str(id) + "_stack"
# How to create a new instance of Stack class at runtime ?
# the __init__ must be run too.
stack = Stack()

How can I create a running average of the last N items in a time series?

My basic idea was to create a linked list, and as each new value comes in, add 1/N times the new value and subtract 1/N times the first value, then move the pointer to first along by one and free the memory that had been associated with first.
This won't ultimately be implemented in Python but just to get the process clear in my head, I tried to write it in Python, but my implementation is flawed. Do I need a doubly linked list for this? Is there an alternative approach (not linked-list based) that would be better?
Here's my attempt so far:
class Link:
def __init__(self,val):
self.next = None
self.value = val
class LinkedList:
def __init__(self,maxlength):
self.current_link = None
self.maxlength = maxlength
self.sum = 0.
self.average = None
self.length = 0
self._first_link = None
def add_link(self,val):
new_link = Link(val)
new_link.next = self.current_link
self.current_link = new_link
if self._first_link is None:
self._first_link = self.current_link
self.sum += val
if self.length < self.maxlength:
self.length += 1
else:
self.sum -= self._first_link.value
self._first_link = self._first_link.next # this line is flawed
self.average = self.sum/self.length
def get_first(self):
return self._first_link.value
# Main
ll = LinkedList(5)
for ii in xrange(10):
ll.add_link(ii)
print ii,ll.get_first(),ll.average
The problem is that _first_link gets set to a value that doesn’t have a next. That is, _first_link gets set to the first item that's added, but its next is None, so I don't see how to move it along by 1 as I want to. This is what makes me wonder if a doubly linked list is needed.
I'd appreciate any advice.
I think the simplest implementation is to use a circular linked list (a.k.a. a ring):
class Link(object):
def __init__(self, value=0.0):
self.next = None
self.value = value
class LinkedRing(object):
def __init__(self, length):
self.sum = 0.0
self.length = length
self.current = Link()
# Initialize all the nodes:
last = self.current
for i in xrange(length-1): # one link is already created
last.next = Link()
last = last.next
last.next = self.current # close the ring
def add_val(self, val):
self.sum -= current.value
self.sum += val
self.current.value = val
self.current = self.current.next
def average(self):
return self.sum / self.length
# Test example:
rolling_sum = LinkedRing(5)
while True:
x = float(raw_input())
rolling_sum.add_val(x)
print(">> Average: %f" % rolling_sum.average())
You can implement this using collections.deque and the numerically stable math for maintaining running averages:
import collections
class AveragingBuffer(object):
def __init__(self, maxlen):
assert( maxlen>1)
self.q=collections.deque(maxlen=maxlen)
self.xbar=0.0
def append(self, x):
if len(self.q)==self.q.maxlen:
# remove first item, update running average
d=self.q.popleft()
self.xbar=self.xbar+(self.xbar-d)/float(len(self.q))
# append new item, update running average
self.q.append(x)
self.xbar=self.xbar+(x-self.xbar)/float(len(self.q))
if __name__=="__main__":
import scipy
ab=AveragingBuffer(10)
for i in xrange(32):
ab.append(scipy.rand())
print ab.xbar, scipy.average(ab.q), len(ab.q)
Okay, I thought of a solution that works in O[1] time. I'm still curious if anyone has a linked-list-based solution, but this solution avoids the LL entirely:
class Recent:
def __init__(self,maxlength):
self.maxlength = maxlength
self.length = 0
self.values = [0 for ii in xrange(maxlength)]
self.index = 0
self.total = 0.
self.average = 0.
def add_val(self,val):
last = self.values[self.index%self.maxlength]
self.values[self.index%self.maxlength] = val
self.total += val
self.total -= last
if self.length < self.maxlength:
self.length += 1
self.average = self.total / self.length
self.index += 1
def print_vals(self):
print ""
for ii in xrange(self.length):
print ii,self.values[ii%self.maxlength]
print "average:",self.average
# Example to show it works
rr = Recent(5)
for ii in xrange(3):
rr.add_val(ii)
rr.print_vals()
for ii in xrange(13):
rr.add_val(ii)
rr.print_vals()

Categories

Resources