Create an insert and pop method on list class - python

I need to implement an insert method (insert(self, index, val)), that inserts val before index, and a pop method (pop(self)), that removes the last element from mylist, onto the MyList class. The behavior should be identical to the methods already available in python.
Note: For the insert method, similarly with the append method already done, the capacity of the array should be doubled if there is no room for an additional element. The pop method should return the element removed from the list, and put None
in its place in the array. If pop was called on an empty list, an IndexError
exception should be raised.
My code thus far:
import ctypes # provides low-level arrays
def make_array(n):
return (n * ctypes.py_object)()
class MyList:
def __init__(self):
self.data = make_array(1)
self.capacity = 1
self.n = 0
def __len__(self):
return self.n
def append(self, val):
if(self.n == self.capacity):
self.resize(2 * self.capacity)
self.data[self.n] = val
self.n += 1
def resize(self, new_size):
new_array = make_array(new_size)
for ind in range(self.n):
new_array[ind] = self.data[ind]
self.data = new_array
self.capacity = new_size
def extend(self, other):
for elem in other:
self.append(elem)
def __getitem__(self, ind):
if not(0 <= ind <= self.n - 1):
raise IndexError('MyList index is out of range')
return self.data[ind]
def __setitem__(self, ind, val):
if not(0 <= ind <= self.n - 1):
raise IndexError('MyList index is out of range')
self.data[ind] = val
mylst1 = MyList()
for i in range(5):
mylst1.append(i)

Related

Ternary Max Heap Python

I am trying to turn a Binary Max Heap into a Ternary Max Heap in Python. My code needs to remain in the same structure as the binary heap below. I need some help figuring out what changes to make. I know the max child method needs to be updated with 3 * i - 1,
3 * i, and 3 * i + 1. I don't know where to begin. Any suggestions would be appreciated.
class BinaryMaxHeap:
def __init__(self):
'''
heap_list[0] = 0 is a dummy value (not used)
'''
self.heap_list = [0]
self.size = 0
def __str__(self):
'''
returns the string representation of the object
'''
return str(self.heap_list)
def __len__(self):
'''
returns a positive integer that represents the length of the object
'''
return self.size
def __contains__(self, item):
'''
instance method, returns boolean value
'''
return item in self.heap_list
def is_empty(self):
'''
compare the size attribute to 0
'''
return self.size == 0
def find_max(self):
'''
the largest item is at the root node (index 1)
'''
if self.size > 0:
max_val = self.heap_list[1]
return max_val
return None
def insert(self, item):
'''
append the item to the end of the list (maintains complete tree property)
violates the heap order property
call percolate up to move the new item up to restore the heap order property
'''
self.heap_list.append(item)
self.size += 1
self.percolate_up(self.size)
def del_max(self):
'''
max item in the tree is at the root
replace the root with the last item in the list (maintains complete tree property)
violates the heap order property
call percolate down to move the new root down to restore the heap property
'''
max_val = self.heap_list[1]
self.heap_list[1] = self.heap_list[self.size]
self.heap_list.pop()
self.size -= 1
self.percolate_down(1)
return max_val
def max_child(self, index):
'''
return the index of the largest child
if there is no right child, return the left child
if there are two children, return the largest of the two
'''
if index*2+1 > self.size:
return index * 2
else:
if self.heap_list[index*2] < self.heap_list[index*2+1]:
return index * 2
else:
return index*2+1
def build_heap(self, alist):
'''
build a heap from a list of keys to establish complete tree property
starting with the first non leaf node
percolate each node down to establish heap order property
'''
index = len(alist)//2 # any nodes past the halfway point are leaves
self.size = len(alist)
self.heap_list = [0] + alist[:]
while (index>0):
self.percolate_down(index)
index -= 1
def percolate_up(self, index):
'''
compare the item at index with its parent
if the item is greater than its parent, swap!
continue comparing until we hit the top of tree
(can stop once an item is swapped into a position where it is greater than its parent)
'''
while index // 2 > 0:
if self.heap_list[index] > self.heap_list[index//2]:
temp = self.heap_list[index//2]
self.heap_list[index//2] = self.heap_list[index]
self.heap_list[index] = temp
index //= 2
def percolate_down(self, index):
'''
compare the item at index with its largest child
if the item is less than its greatestest child, swap!
continue continue while there are children to compare with
(can stop once an item is swapped into a position where it is less than both children)
'''
while (index * 2) <= self.size:
mc = self.max_child(index)
if self.heap_list[index] < self.heap_list[mc]:
temp = self.heap_list[index]
self.heap_list[index] = self.heap_list[mc]
self.heap_list[mc] = temp
index = mc
While a dummy entry can still be interesting for a binary heap implementation, to get the same "benefit" for a ternary heap, you would need 2 dummies. It is better to just adapt the index calculations and have no dummy needs. Without the dummy it becomes also overkill to have a size attribute, since it always corresponds to the length of the list.
The implementation for a ternary tree just needs to adapt all those occurrences where a coefficient of 2 is used and adapt them to use 3 (and the shift to get the index right).
I would not have created a separate build_heap method, and certainly not as an instance method, but since you indicated you want the "same structure", I left it like that.
class TernaryMaxHeap:
def __init__(self):
self.heap_list = [] # No more dummy
# No more size attribute. A list knows its size.
def __str__(self):
return str(self.heap_list)
def __len__(self):
return len(self.heap_list)
def __contains__(self, item):
return item in self.heap_list
def is_empty(self):
return not self.heap_list
def find_max(self):
if self.heap_list:
return self.heap_list[0] # No more dummy
def insert(self, item):
self.heap_list.append(item)
self.percolate_up(len(self)-1)
def del_max(self):
max_val = self.heap_list[0]
self.heap_list[0] = self.heap_list[-1]
self.heap_list.pop()
if self.heap_list:
self.percolate_down(0)
return max_val
def max_child(self, index):
child = index * 3 + 1
if child >= len(self) - 1:
return child
# Generic with range, using coefficient 3
return max((self.heap_list[child], child) for child in range(child, min(child + 3, len(self))))[1]
# NB: This alist argument should have better been integrated with the constructor:
def build_heap(self, alist):
self.heap_list = alist[:] # No dummy
for index in range((len(alist) - 2)//3, -1, -1): # Use divisor 3, and pythonic looping
self.percolate_down(index)
def percolate_up(self, index):
val = self.heap_list[index]
parent = (index - 1) // 3 # Coefficient 3, without dummy
while index and self.heap_list[parent] < val:
self.heap_list[index] = self.heap_list[parent]
index = parent
parent = (index - 1) // 3
self.heap_list[index] = val
def percolate_down(self, index):
val = self.heap_list[index]
child = self.max_child(index)
while child < len(self) and val < self.heap_list[child]:
self.heap_list[index] = self.heap_list[child]
index = child
child = self.max_child(index)
self.heap_list[index] = val

Circular Array-Based Queue Insert Class Method - Python

I am trying to implement the insert method of a circular array-based queue, however am unable to update the rear of the queue. Here is my code:
def __init__(self, max_size):
"""
-------------------------------------------------------
Initializes an empty queue. Data is stored in a fixed-size list.
Use: cq = Queue(max_size)
-------------------------------------------------------
Parameters:
max_size - maximum size of the queue (int > 0)
Returns:
a new Queue object (Queue)
-------------------------------------------------------
"""
assert max_size > 0, "Queue size must be > 0"
self._max_size = max_size
self._values = [None] * self._max_size
self._front = 0
self._rear = 0
self._count = 0
def insert(self, value):
'''-------------------------------------------------------
Adds a copy of value to the rear of the queue.
Use: cq.insert( value )
-------------------------------------------------------
Parameters:
value - a data element (?)
Returns:
None
-------------------------------------------------------'''
assert (self._count < self._max_size), 'queue is full'
self._values.append(deepcopy(value))
self._count += 1
self._rear = (self._rear - 1) % self._count
return
Any suggestions?
edit:
here is the remove implementation:
def remove(self):
'''-------------------------------------------------------
Removes and returns value from the queue.
Use: v = cq.remove()
-------------------------------------------------------
Returns:
value - the value at the front of the queue - the value is
removed from the queue (?)
-------------------------------------------------------'''
assert (self._count > 0), 'Cannot remove from an empty queue'
value = self._values[self._front]
self._front = (self._front + 1) % self._count
self._count += -1
return value
When you add items by appending, you are extending your list beyond the max length that you pre-allocated it to. You then update self._rear as if you were going to use it as the insert index, but never actually use it for anything. I have implemented your code with only very minor changes beyond variable names (in order to make more sense to me), and utilizing self._rear (now: self._write_cursor) in the way I believe you intended.
class CQ: #Circular Queue
def __init__(self, maxsize):
self._maxsize = maxsize
self._write_cursor = 0
self._read_cursor = 0
self._len = 0
self._values = [None] * maxsize
def insert(self, item):
if self._len < self._maxsize:
self._values[self._write_cursor] = item
self._write_cursor = (self._write_cursor + 1) % self._maxsize
self._len = self._len + 1
else:
raise IndexError('can\'t push to full queue')
def remove(self):
if self._len > 0:
out = self._values[self._read_cursor]
self._read_cursor = (self._read_cursor + 1) % self._maxsize
self._len -= 1
return out
else:
raise IndexError('can\'t pop from empty queue')

Return lambda Node < Node

I'm receiving this compiler error when putting a Node onto a min-priority queue.
TypeError: '<' not supported between instances of 'Node' and 'Node'
Here is where it fails
from queue import PriorityQueue
def huffman(text):
A = frequency(text) # returns a dictionary {(frequency, character),...}
q = PriorityQueue()
heap = build_min_heap(A) # builds min heap
while heap:
temp = pop_heap(heap) # format (frequency, character)
----> q.put(Node(temp[1],temp[0],None,None))
# Node(character, frequency, left child, right child)
def min_heapify(A, i, key=lambda a: a):
lefti = 2 * i + 1
righti = 2 * i + 2
heap_size = len(A)
--->if lefti < heap_size and key(A[lefti]) < key(A[i]):
/anaconda3/lib/python3.6/queue.py in put(self, item, block, timeout)
141 raise Full
142 self.not_full.wait(remaining)
--> 143 self._put(item)
144 self.unfinished_tasks += 1
145 self.not_empty.notify()
/anaconda3/lib/python3.6/queue.py in _put(self, item)
225
226 def _put(self, item):
--> 227 heappush(self.queue, item)
228
229 def _get(self):
I found a workaround by adding an "lt" function to the Node class.
def __lt__(self, other):
return self.frequency < other.frequency
However, is there another way to fix this using lambda expressions or modifying the min-priority queue in some way?
Maybe a key function perhaps? I understand what key(value) is doing but I don't know how would I interpret it as a Node. I tried something like the following, but it didn't work.
def key(item):
if instanceof(item, Node):
return item.frequency
Also to note that the heap functions also process int values and other types. This is way later in the code where I'm passing Nodes to the heap/queue.
Note: The Node is sorted by frequency.
Here is my Node class
class Node():
def __init__(self, character=None, frequency=None, left=None, right=None):
self.character = character
self.frequency = frequency
self.left = left
self.right = right
def isLeaf(self):
return self.left is None and self.right is None
def __lt__(self, other):
return self.frequency < other.frequency
def __repr__(self):
return 'Node({}, {}, {}, {})'.format(self.character,
self.frequency,
self.left, self.right)
def min_heapify(A, i, key=lambda a: a):
lefti = 2 * i + 1
righti = 2 * i + 2
heap_size = len(A)
if lefti < heap_size and key(A[lefti]) < key(A[i]):
smallesti = lefti
else:
smallesti = i
if righti < heap_size and key(A[righti]) < key(A[smallesti]):
smallesti = righti
if smallesti != i:
A[i], A[smallesti] = A[smallesti], A[i]
min_heapify(A, smallesti, key)
def build_min_heap(A, key=lambda a: a):
for i in range(len(A) // 2 - 1, -1, -1):
swaps = min_heapify(A, i, key)
return A
A final word, I understand that "lt" works in the Node class, but I'm trying to figure out another solution that doesn't involve modifying the Node class because other sites have comments that say to use a lambda expression (e.g. The key function should return the frequency stored in the argument to key, which should be a Node.; do we need to write the key function? Yes. It can be a simple lambda expression.) but they are vague in how to accomplish that.

Defining multiple variances of __iter__ in a class

I am writing a game of Connect 4 and have a Grid class that resembles the 2-dimensional grid that the game is played in. The underlying data structure of my Grid class is an instance variable self.grid - a 2-dimensional list.
I have overwritten the __iter__ method as such:
def __iter__(self):
for row in range(self.numRows):
for col in range(self.numCols):
yield self.grid[row][col]
which I can then call as:
for cell in grid:
# do something with yielded cell
At some points, I need to iterate over just a specified row or a specified column. Instead of writing
col = 0
for row in range(grid.numRows):
# do something with grid.grid[row][col]
is there any Pythonic, readable way to define a 2nd and 3rd __iter__ method along the lines of:
def __iter__(self, col)
for row in range(self.numRows):
yeild self.grid[row][col]
which would be called as:
for row in grid(col=0):
# do something with the yielded cell
and then the same, but with a specified row?
You can certainly have as many of these methods as you like. You just can't call them all __iter__(), because Python does not support method overloading. You could, for example, do this:
def rows(self, col):
for row in range(self.numRows):
yield self.grid[row][col]
def cols(self, row):
for col in range(self.numCols):
yield self.grid[row][col]
def cells(self):
for row in range(self.numRows):
for col in range(self.numCols):
yield self.grid[row][col]
You would then write something like
for row in grid.rows(col=0):
# Do something
Sure you can do that, no need to add special methods. Just add iterators, python 3 code below:
ALL = 0
ROW = 1
COL = 2
class db:
def __init__(self, n):
self.n = n
def __iter__(self):
return db_iter_all(self.n)
def __call__(self, what = ALL):
if what == ALL:
return db_iter_all(self.n)
if what == ROW:
return db_iter_row(self.n)
if what == COL:
return db_iter_col(self.n)
raise ValueError("What what?")
class db_iter_all:
def __init__(self, n):
self.i = 0
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.i > self.n:
raise StopIteration()
r = self.i
self.i += 1
return r
class db_iter_row:
def __init__(self, n):
self.i = 0
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.i > self.n:
raise StopIteration()
r = self.i
self.i += 3
return r
class db_iter_col:
def __init__(self, n):
self.i = 0
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.i > self.n:
raise StopIteration()
r = self.i
self.i += 5
return r
And simple example how to use it
grid = db(15)
for k in grid:
print(k)
for k in grid(ROW):
print(k)
for k in grid(COL):
print(k)

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