My question is pretty straightforward. Is there a library in Python that has a data structure that can represent items on a shelf? Essentially, it would need to be a matrix where each row is the same length but the items in each row can be of varying lengths.
Here's a visual representation:
This should tell you if two shelf items overlap on the shelves (in the sense that one is below or above the other).... Assuming you know where your shelf items are by index.
class Item(list):
pass
shelves = [
[Item([1, 2, 3, 4]) ,Item([5, 6 ])],
[Item([7, 8]),Item([9]),Item([10, 11]), Item([12])]
]
# shelf items are indexed by two indices, shelf and item
def shelf_items_overlap(shelves, shelf1, item1, shelf2, item2):
item1_real_index = sum(map(len, shelves[shelf1][:item1]))
item2_real_index = sum(map(len, shelves[shelf2][:item2]))
return range_overlaps(
item2_real_index, item2_real_index + len(shelves[shelf2][item2]),
item1_real_index, item1_real_index + len(shelves[shelf1][item1])
)
def range_overlaps(x11,x12,x21,x22):
''' return if (x11, x12) overlaps (x21, x22) '''
return x21<=x12<=x22 or x21<=x11<=x22 or x11<=x21<=x12 or x11<=x22<=x12
print(shelf_items_overlap(shelves, 0, 1, 1, 0), shelf_items_overlap(shelves, 0, 1, 1, 2))
I think your problem should make a better use of classes than arrays. I know that this maybe this is not the answer you're looking but here is a quick code of a class implementation of items and shelf_rows that gets you the info of what it is in a shelf.
class Item ():
# Init the item class with a lenght
def __init__(self, length, name = 'Item'):
self.name = name
self.length = length
# Allow us to use the len method on item to get the length
def __len__(self):
return self.length
# Show us a clear print of the Item
def __repr__(self):
return '%r of length (%r)' % (self.name,self.length)
class ShelfRow ():
#Make a ShelfRow of a fixed length
def __init__ (self, length):
self.length = length
self.space_left = length
self.items = []
#Use append like if it was a list
def append (self,Item):
if Item.length > self.space_left:
return 'This should throw an error because the length is too long for the space left'
else:
self.items.append (Item)
self.space_left = self.space_left - Item.length
# Use the __getitem__ special method to get the position of an item
def __getitem__(self,position):
return self.items[position]
#Print the content of items
def __repr__(self):
return '%r' % self.items
# Make three items
item_a = Item(4, 'Big Box')
item_b = Item(2, 'Medium Box')
item_c = Item(2, 'Medium Box')
item_d = Item(8, 'Super Big Box')
#Make a shelfRow
shelf_row1 = ShelfRow(8)
shelf_row2 = ShelfRow(8)
#Populate shelfs
shelf_row1.append(item_a)
shelf_row1.append(item_b)
shelf_row1.append(item_c)
shelf_row2.append(item_d)
#Make a shelf, it could be an object too (it should probably)
shelf = [shelf_row1,shelf_row2]
#Print what is in every shelf_row
for shelf_row in shelf:
print(shelf_row)
The other answer is probably the closest to what you want but I get the feeling that maybe you could do for something a little more abstract to solve your problem.
Anyways I hope that this was useful.
I am not aware of any module, but this seems like a traditional "Make this data structure" type of question. So here's a base you can work with, and it may seem similar to other questions, but this should work and satisfy your needs. Its pretty much an implementation that uses the idea used in page allocation as your problem can be seen as you need frame to contain a certain amount of pages of a fixed size. It could be optimized by using a better algorithm (or process to add) but I forgot which one I used is called nor did I feel like implementing something more complicated.
class Item:
def set_width(self, width):
self.width = width
def get_width(self):
return self.width
def __init__(self, width=0):
self.width = width
class Shelf:
def add_item(self, item):
if item.get_width() > self.max_width:
print("Item will not fit in the shelf.")
return False
row = 0
while (row < len(self.rows)):
if (self.get_row_tot(row) + item.get_width()) <= self.max_width:
self.rows[row].append(item)
return True
row += 1
# Stop here, we want to prevent addition of a shelf
if max_height != -1 and row >= max_height:
print("Item will not fit in the shelf.")
return False
self.rows.append([item])
return True
def get_row_tot(self, row):
tot = 0
for i in self.rows[row]:
tot += i.get_width()
return tot
def remove_item(self, row, item):
if row < len(self.rows):
self.rows[row].remove(item)
return True
else:
print("Row does not exist")
return False
def __init__(self, max_width, max_height=-1):
"""
max_height = -1 means no height limit
"""
self.max_width = max_width
self.max_height = max_height
self.rows = []
self.head = 0
a = Shelf(3)
b = Item(1)
c = Item(1)
d = Item(2)
e = Item(2)
a.add_item(b)
a.add_item(c)
a.add_item(d)
a.remove_item(0, c)
a.remove_item(2, e)
a.add_item(e)
Like I said, this could be optimized and some additions could be made such as a method to swap, set, search, sort and so on so forth. You can also modify Item to be an object you're working with.
I have an entire Deque Array class that looks like this:
from collections import deque
import ctypes
class dequeArray:
DEFAULT_CAPACITY = 10 #moderate capacity for all new queues
def __init__(self):
self.capacity = 5
capacity = self.capacity
self._data = self._make_array(self.capacity)
self._size = 0
self._front = 0
def __len__(self):
return self._size
def __getitem__(self, k): #Return element at index k
if not 0 <= k < self._size:
raise IndexError('invalid index')
return self._data[k]
def isEmpty(self):
if self._data == 0:
return False
else:
return True
def append(self, item): #add an element to the back of the queue
if self._size == self.capacity:
self._data.pop(0)
else:
avail = (self._front + self._size) % len(self._data)
self._data[avail] = item
self._size += 1
#def _resize(self, c):
#B = self._make_array(c)
#for k in range(self._size):
#B[k] = self._A[k]
#self._data = B
#self.capacity = capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
def removeFirst(self):
if self._size == self.capacity:
self._data.pop(0)
else:
answer = self._data[self._front]
self._data[self._front] = None
self._front = (self._front + 1) % len(self._data)
self._size -= 1
print(answer)
def removeLast(self):
return self._data.popleft()
def __str__(self):
return str(self._data)
and when I try to print the deque in the main it prints out something like this,
<bound method dequeArray.__str__ of <__main__.dequeArray object at 0x1053aec88>>
when it should be printing the entire array. I think i need to use the str function and i tried adding
def __str__(self):
return str(self._data)
and that failed to give me the output. I also tried just
def __str__(self):
return str(d)
d being the deque array but I still am not having any success. How do I do i get it to print correctly?
you should call the str function of each element of the array that is not NULL, can be done with the following str function:
def __str__(self):
contents = ", ".join(map(str, self._data[:self._size]))
return "dequeArray[{}]".format(contents)
What I get when I try to q = dequeArray(); print(q) is <__main__.py_object_Array_5 object at 0x006188A0> which makes sense. If you want it list-like, use something like this (print uses __str__ method implicitly):
def __str__(self):
values = []
for i in range(5):
try:
values.append(self._data[i])
except ValueError: # since accessing ctypes array by index
# prior to assignment to this index raises
# the exception
values.append('NULL (never used)')
return repr(values)
Also, several things about the code:
from collections import deque
This import is never user and should be removed.
DEFAULT_CAPACITY = 10
is never used. Consider using it in the __init__:
def __init__(self, capacity=None):
self.capacity = capacity or self.DEFAULT_CAPACITY
This variable inside __init__ is never user and should be removed:
capacity = self.capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
Though this is a valid code, you're doing it wrong unless you're absolutely required to do it in your assignment. Ctypes shouldn't be used like this, Python is a language with automated memory management. Just return [] would be fine. And yes, variable c is never used and should be removed from the signature.
if self._data == 0
In isEmpty always evaluates to False because you're comparing ctypes object with zero, and ctypes object is definitely not a zero.
I am having a problem with my code. I keep getting the following error:
AttributeError: 'NoneType' object has no attribute 'insert'
Could anyone tell me why I am getting this error? Here is my code and the snippit where it is causing the most problem below that.
class Heap(object):
def __init__(self, items=None):
'''Post: A heap is created with specified items.'''
self.heap = [None]
if items is None:
self.heap_size = 0
else:
self.heap += items
self.heap_size = len(items)
self._build_heap()
def size(self):
'''Post: Returns the number of items in the heap.'''
return self.heap_size
def _heapify(self, position):
'''Pre: Items from 0 to position - 1 satisfy the Heap property.
Post: Heap Property is satisfied for the entire heap.'''
item = self.heap[position]
while position * 2 <= self.heap_size:
child = position * 2
# If the right child, determine the maximum of two children.
if (child != self.heap_size and self.heap[child+1] > self.heap[child]):
child += 1
if self.heap[child] > item:
self.heap[position] = self.heap[child]
position = child
else:
break
self.heap[position] = item
def delete_max(self):
'''Pre: Heap property is satisfied
Post: Maximum element in heap is removed and returned. '''
if self.heap_size > 0:
max_item = self.heap[1]
self.heap[1] = self.heap[self.heap_size]
self.heap_size -= 1
self.heap.pop()
if self.heap_size > 0:
self._heapify(1)
return max_item
def insert(self, item):
'''Pre: Heap Property is Satisfied.
Post: Item is inserted in proper location in heap.'''
self.heap_size += 1
# extend the length of the list.
self.heap.append(None)
position = self.heap_size
parent = position // 2
while parent > 0 and self.heap[parent] < item:
# Move the item down.
self.heap[position] = self.heap[parent]
position = parent
parent = position // 2
# Puts the new item in the correct spot.
self.heap[position] = item
def _build_heap(self):
''' Pre: Self.heap has values in 1 to self.heap_size
Post: Heap property is satisfied for entire heap. '''
# 1 through self.heap_size.
for i in range(self.heap_size // 2, 0, -1): # Stops at 1.
self._heapify(i)
def heapsort(self):
'''Pre: Heap Property is satisfied.
Post: Items are sorted in self.heap[1:self.sorted_size].'''
sorted_size = self.heap_size
for i in range(0, sorted_size -1):
# Since delete_max calls pop to remove an item, we need to append a dummy value to avoid an illegal index.
self.heap.append(None)
item = self.delete_max()
self.heap[sorted_size - i] = item
That is the main heap function where I need to take the functions from. This is the part of the code that is giving me the trouble.
def insert(self, item):
'''Pre: Heap Property is Satisfied.
Post: Item is inserted in proper location in heap.'''
self.heap_size += 1
# extend the length of the list.
self.heap.append(None)
position = self.heap_size
parent = position // 2
while parent > 0 and self.heap[parent] < item:
# Move the item down.
self.heap[position] = self.heap[parent]
position = parent
parent = position // 2
# Puts the new item in the correct spot.
self.heap[position] = item
Here is my PriorityQueue class which calls the functions and helps me implement them into a Priority Queue.
from MyHeap import Heap
class PriorityQueue(object):
def __init__(self):
self.heap = None
def enqueue(self, item, priority):
'''Post: Item is inserted with specified priority in the PQ.'''
self.heap.insert(priority, item)
def first(self):
'''Post: Returns but does not remove the highest priority item from the PQ.'''
return self.heap[0]
def dequeue(self):
'''Post: Removes and returns the highest priority item from the PQ.'''
if Heap.size() is None:
raise ValueError("Error your queue is empty.")
self.first()
self.heap.delete_max()
def size(self):
'''Post: Returns the number of items in the PQ.'''
return Heap.size()
So in this code the enqueue calls the insert function.
def enqueue(self, item, priority):
'''Post: Item is inserted with specified priority in the PQ.'''
self.heap.insert(priority, item)
Finally here is my test code:
from PriorityQueue import PriorityQueue
PQ = PriorityQueue()
PQ.enqueue(1, 200)
PQ.enqueue(2, 450)
PQ.enqueue(3, 204)
It is probably a simple fix, but does anyone know why I keep getting the Attribute Error?
That's because you initialize self.heap with None:
class PriorityQueue(object):
def __init__(self):
self.heap = None
You probably should initialize with Heap():
class PriorityQueue(object):
def __init__(self):
self.heap = Heap()
Your code has also other issues:
You should call self.heap.insert with only one parameter (you're calling with two):
def enqueue(self, item, priority):
'''Post: Item is inserted with specified priority in the PQ.'''
self.heap.insert((priority, item))
You should use self.heap.size(), not Heap.size():
if self.heap.size() == 0:
raise ValueError("Error your queue is empty.")
and also
def size(self):
'''Post: Returns the number of items in the PQ.'''
return self.heap.size()
You should return the value from self.heap.delete_max():
def dequeue(self):
'''Post: Removes and returns the highest priority item from the PQ.'''
if self.heap.size() == 0:
raise ValueError("Error your queue is empty.")
return self.heap.delete_max()
first must return the [1] element in the heap, because [0] is always None:
def first(self):
'''Post: Returns but does not remove the highest priority item from the PQ.'''
return self.heap.heap[1]
"Write a function named stutter that accepts a queue of integers as a parameter and replaces every element of the queue with two copies of that element in the original queue."
Example:
q1 = Queue()
queue.enqueue(1)
queue.enqueue(2)
queue.enqueue(3)
stutter(q1)
while not queue.isempty():
print(queue.dequeue(), end=' ')
should give answer as "1 1 2 2 3 3"
class Queue:
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def enqueue(self, item):
self.items.insert(0,item)
def dequeue(self):
return self.items.pop()
def size(self):
return len(self.items)
def check_empty(self):
if self.items == []:
return True
def stutter(Q):
queue=Queue()
stack = Stack()
while not queue.isempty():
stack.push(queue.dequeue())
while not stack.isempty():
queue.enqueue(stack.pop())
That is the code that i have written, with that i can get it to print once and once only, i can't get it to duplicate and sort in order.
Try using this (can't test at the moment):
def stutter(queue):
# iterate all items
for _ in range(queue.size()):
# store item in local context
item = queue.dequeue()
# push two *references* to item into the queue
queue.enqueue(item)
queue.enqueue(item)
This will iterate all items once, immediately pushing two copes to the back of the queue. The first pushed items should be the first once this iteration is over.
Notice that objects will be not be duplicated,and there will be two references to the same object in the queue.
Tip: there is already a queue implementation in Python. You can use it by importing queue
In [17]:
def stutter(q):
for i in range(q.size()):
elm = q.dequeue()
q.enqueue(elm)
q.enqueue(elm)
In [18]:
q1 = Queue()
q1.enqueue(1)
q1.enqueue(2)
q1.enqueue(3)
stutter(q1)
print q1
[3, 3, 2, 2, 1, 1]
Note, I added a str method to the Queue class to see results.
class Queue:
# SAME AS BEFORE
def __str__(self):
return str(self.items)
You can also cheat because python does not have private instance variables. I would not recommend it as an option.
def stutter(q):
q.items = sorted([elm for elm in q.items] + [elm for elm in q.items])
If you want to return using the desired output:
q1 = Queue()
q1.enqueue(1)
q1.enqueue(2)
q1.enqueue(3)
stutter(q1)
print(' '.join([str(elm) for elm in q1.items]))
1 1 2 2 3 3
I'm writing a class for a simple game of 4 in a row, but I'm running into a problem calling a method in the same class. Here's the whole class for the sake of completeness:
class Grid:
grid = None
# creates a new empty 10 x 10 grid
def reset():
Grid.grid = [[0] * 10 for i in range(10)]
# places an X or O
def place(player,x,y):
Grid.grid[x][y] = player
# returns the element in the grid
def getAt(x,y):
return Grid.grid[x][y]
# checks for wins in a certain direction
def checkLine(player,v,count,x,y):
x = x+v[0]
y = y+v[1]
if x < 0 or x > 9:
return
if y < 0 or y > 9:
return
if Grid.grid[x][y] == p:
count = count+1
if count == 4:
return True
checkLine(player,v,count,x,y)
return False
# returns the number of the player that won
def check():
i = 'i'
for x in range(0,10):
for y in range(0,10):
if Grid.grid[x][y] > 0:
p = Grid.grid[x][y]
f = checkLine(p,0,array(i,[1,0]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[0,1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[1,1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[-1,0]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[0,-1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[-1,-1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[1,-1]),x,y)
if f:
return p
f = checkLine(p,0,array(i,[-1,1]),x,y)
if f:
return p
return 0
reset = staticmethod(reset)
place = staticmethod(place)
getAt = staticmethod(getAt)
check = staticmethod(check)
checkLine = staticmethod(checkLine)
I'm trying to call checkLine() from check(), but I get the error "NameError: global name 'checkLine' is not defined". When I call Grid.checkLine() instead, I get "TypeError: 'module' object is not callable"
How do I call checkLine()?
EDIT:
#beer_monk
class Grid(object):
grid = None
# creates a new empty 10 x 10 grid
def reset(self):
Grid.grid = [[0] * 10 for i in range(10)]
# places an X or O
def place(self,player,x,y):
Grid.grid[x][y] = player
# returns the element in the grid
def getAt(self,x,y):
return Grid.grid[x][y]
# checks for wins in a certain direction
def checkLine(self,player,v,count,x,y):
x = x+v[0]
y = y+v[1]
if x < 0 or x > 9:
return
if y < 0 or y > 9:
return
if Grid.grid[x][y] == p:
count = count+1
if count == 4:
return True
checkLine(self,player,v,count,x,y)
return False
# returns the number of the player that won
def check(self):
i = 'i'
for x in range(0,10):
for y in range(0,10):
if Grid.grid[x][y] > 0:
p = Grid.grid[x][y]
for vx in range(-1,2):
for vy in range(-1,2):
f = self.checkLine(p,0,array(i,[vx,vy]),x,y)
if f:
return p
return 0
reset = staticmethod(reset)
place = staticmethod(place)
getAt = staticmethod(getAt)
check = staticmethod(check)
checkLine = staticmethod(checkLine)
Get rid of the class. Use plain functions and module level variable for grid.
The class is not helping you in any way.
PS. If you really want to call checkline from within the class, you'd call Grid.checkline. For example:
class Foo:
#staticmethod
def test():
print('Hi')
#staticmethod
def test2():
Foo.test()
Foo.test2()
prints
Hi
Syntax:
class_Name.function_Name(self)
Example:
Turn.checkHoriz(self)
A reworked example (hopefully showing a better use of classes!)
import itertools
try:
rng = xrange # Python 2.x
except NameError:
rng = range # Python 3.x
class Turn(object):
def __init__(self, players):
self.players = itertools.cycle(players)
self.next()
def __call__(self):
return self.now
def next(self):
self.now = self.players.next()
class Grid(object):
EMPTY = ' '
WIDTH = 10
HEIGHT = 10
WINLENGTH = 4
def __init__(self, debug=False):
self.debug = debug
self.grid = [Grid.EMPTY*Grid.WIDTH for i in rng(Grid.HEIGHT)]
self.player = Turn(['X','O'])
def set(self, x, y):
if self.grid[y][x]==Grid.EMPTY:
t = self.grid[y]
self.grid[y] = t[:x] + self.player() + t[x+1:]
self.player.next()
else:
raise ValueError('({0},{1}) is already taken'.format(x,y))
def get(self, x, y):
return self.grid[y][x]
def __str__(self):
corner = '+'
hor = '='
ver = '|'
res = [corner + hor*Grid.WIDTH + corner]
for row in self.grid[::-1]:
res.append(ver + row + ver)
res.append(corner + hor*Grid.WIDTH + corner)
return '\n'.join(res)
def _check(self, s):
if self.debug: print("Check '{0}'".format(s))
# Exercise left to you!
# See if a winning string exists in s
# If so, return winning player char; else False
return False
def _checkVert(self):
if self.debug: print("Check verticals")
for x in rng(Grid.WIDTH):
winner = self._check([self.get(x,y) for y in rng(Grid.HEIGHT)])
if winner:
return winner
return False
def _checkHoriz(self):
if self.debug: print("Check horizontals")
for y in rng(Grid.HEIGHT):
winner = self._check([self.get(x,y) for x in rng(Grid.WIDTH)])
if winner:
return winner
return False
def _checkUpdiag(self):
if self.debug: print("Check up-diagonals")
for y in rng(Grid.HEIGHT-Grid.WINLENGTH+1):
winner = self._check([self.get(d,y+d) for d in rng(min(Grid.HEIGHT-y, Grid.WIDTH))])
if winner:
return winner
for x in rng(1, Grid.WIDTH-Grid.WINLENGTH+1):
winner = self._check([self.get(x+d,d) for d in rng(min(Grid.WIDTH-x, Grid.HEIGHT))])
if winner:
return winner
return False
def _checkDowndiag(self):
if self.debug: print("Check down-diagonals")
for y in rng(Grid.WINLENGTH-1, Grid.HEIGHT):
winner = self._check([self.get(d,y-d) for d in rng(min(y+1, Grid.WIDTH))])
if winner:
return winner
for x in rng(1, Grid.WIDTH-Grid.WINLENGTH+1):
winner = self._check([self.get(x+d,d) for d in rng(min(Grid.WIDTH-x, Grid.HEIGHT))])
if winner:
return winner
return False
def isWin(self):
"Return winning player or False"
return self._checkVert() or self._checkHoriz() or self._checkUpdiag() or self._checkDowndiag()
def test():
g = Grid()
for o in rng(Grid.WIDTH-1):
g.set(0,o)
g.set(Grid.WIDTH-1-o,0)
g.set(Grid.WIDTH-1,Grid.HEIGHT-1-o)
g.set(o,Grid.HEIGHT-1)
print(g)
return g
g = test()
print g.isWin()
Unlike java or c++, in python all class methods must accept the class instance as the first variable. In pretty much every single python code ive seen, the object is referred to as self. For example:
def reset(self):
self.grid = [[0] * 10 for i in range(10)]
See http://docs.python.org/tutorial/classes.html
Note that in other languages, the translation is made automatically
There are multiple problems in your class definition. You have not defined array which you are using in your code. Also in the checkLine call you are sending a int, and in its definition you are trying to subscript it. Leaving those aside, I hope you realize that you are using staticmethods for all your class methods here. In that case, whenever you are caling your methods within your class, you still need to call them via your class's class object. So, within your class, when you are calling checkLine, call it is as Grid.checkLine That should resolve your NameError problem.
Also, it looks like there is some problem with your module imports. You might have imported a Module by name Grid and you have having a class called Grid here too. That Python is thinking that you are calling your imported modules Grid method,which is not callable. (I think,there is not a full-picture available here to see why the TypeError is resulting)
The best way to resolve the problem, use Classes as they are best used, namely create objects and call methods on those objects. Also use proper namespaces. And for all these you may start with some good introductory material, like Python tutorial.
Instead of operating on an object, you are actually modifying the class itself. Python lets you do that, but it's not really what classes are for. So you run into a couple problems
-You will never be able to make multiple Grids this way
the Grid can't refer back to itself and e.g. call checkLine
After your grid definition, try instantiating your grid and calling methods on it like this
aGrid = Grid()
...
aGrid.checkLine()
To do that you, you first need to modify all of the method definitions to take "self" as your first variable and in check, call self.checkLine()
def check(self):
...
self.checkLine()
...
Also, your repeated checking cries out for a FOR loop. You don't need to write out the cases.
Java programmer as well here, here is how I got it to call an internal method:
class Foo:
variable = 0
def test(self):
self.variable = 'Hi'
print(self.variable)
def test2(self):
Foo.test(self)
tmp = Foo()
tmp.test2()