Matrix in Python That Can Represent Items on a Shelf - python

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.

Related

py: runningmax with double deque and rampup ok?

I have implemented this runningMax class:
class RunningMax():
def __init__(self,window):
self.window = window
self.values = deque()
self.maxima = deque()
return
def append(self,x):
self.values.append(x)
i = 0
while (len(self.maxima) > 0) and (x > self.maxima[-1]) and (i < min(len(self.values),self.window)):
# pop all values at back that are smaller than new value
self.maxima.pop()
i += 1
self.maxima.append(x)
return
def pop(self):
full = len(self.values) == self.window
if self.maxima[0]==self.values[0] and full:
# if a value is about to leave the sliding window, kick it from maxima
max = self.maxima.popleft()
else:
max = self.maxima[0]
if full:
self.values.popleft()
return max
def compute_max(a,window):
rm = RunningMax(window)
maxs = []
for i,ai in enumerate(a):
rm.append(ai)
maxs.append(rm.pop())
return maxs
The output of compute_max(a,window) compares exactly to:
pd.Series(a).rolling(window,min_periods=1).max()
So, its implemented correctly. Just would like to ask if there is any potential for improvement here? Anything that could be written more optimally basically.
Thanks!

Python get highest value that is equal to or less than x

So I have this one list hex_rows. This list has thousands of entries of type HexRow.
class HexRow:
def __init__(self, byte_count, address, record_type, data, checksum):
self.byte_count = byte_count
self.min_addr = address
self.record_type = record_type
self.data = data
self.checksum = checksum
I also have a dictionary ex_obj.charics. This one has a lot of fields, but the only relevant one is n_Address.
ex_obj_hex_list = []
for ex_val in ex_obj.charics.values():
templist = [t for t in hex_rows if t.min_addr <= ex_val.n_Address]
tuple = (ex_val, templist[-1])
ex_obj_hex_list.append(tuple)
As you can see, I'm trying to find the hex_row item where the min_addr field is equal to n_Address. If there is no equal value I want to get the highest min_addr value that is less than n_Address. Although the above code is working, it is very slow. I read about bisect somewhere but I'm not able to figure out how it works
So I figured out how to get Bisect to work:
ex_val_hex_addr.append = []
for ex_val in ex_obj.charics.values():
i = bisect_left(hex_rows, ex_val.n_Address)
ex_val_hex_addr.append((ex_val, hex_rows[i - 1]))
I also needed to adjust my constructor for the HexRow object
class HexRow:
def __init__(self, byte_count, address=None, record_type=None, data=None, checksum=None):
if address is None:
self.num_low_addr = byte_count
else:
self.byte_count = byte_count
self.min_addr = address
self.record_type = record_type
self.data = data
self.checksum = checksum
def __lt__(self, other):
return self.num_low_addr <= other
def __repr__(self):
return 'Foo({})'.format(self.num_low_addr)

Making a graph class iterate using a dictionary

I am trying to build a iterable graph class with python 2.7. I want to be able to iterate though a dictionary containing the vertexes.
Cutting and pasting from https://github.com/joeyajames has got me so far but now I am confused as to how to make this work so that
I can test vertices dict for the presence of an vertice and add if not present. This part is maybe unneeded.
"if (a not in gra ):" because the validation is done in the Graph class itself.
The expected output is a dictionary with the vertices as keys. Actualy im not even sure a list is not better object to use.
class Vertex(object):
def __init__(self, n):
self.name = n
self.neighbors = list()
self.discovery = 0
self.finish = 0
self.color = 'black'
def add_neighbor(self, v):
if v not in self.neighbors:
self.neighbors.append(v)
self.neighbors.sort()
class Graph(object):
def __init__(self,size):
self.vertices = {}
self.hops = 0
self.count = 0
self.limit = size
def __iter__(self):
return self
def next(self):
self.count += 1
if self.count > self.limit:
raise StopIteration
def add_vertex(self,vertex):
if isinstance(vertex, Vertex) and vertex.name not in self.vertices:
self.vertices[vertex.name] = vertex
return True
else:
return False
def add_edge(u,v):
if u in self.vertices and v in self.vertices:
for key, value in self.vertices.items():
if key == u:
value.add_neighbor(v)
if key == v:
value.add_neighbor(u)
return True
else:
return False
def _dfs(self, vertex):
global hops
vertex.color = 'red'
vertex.discovery = hops
hops += 1
for v in vertex.neighbors:
if self.vertices[v].color == 'black':
self._dfs(self.vertices[v])
vertex.color = 'blue'
vertex.finish = hops
time += 1
input = ((5,3),(4 ,2),(0,1),(2 3),(0 4))
N,l = input[0]
print "N is " + str(N)
print "l is " + str(l)
gra = Graph(N)
for i in xrange(1,l):
a,b = input[i]
# Store a and b as vertices in graph object
print "a is " + str(a) + " b is " + str(b)
if (a not in gra ):
print "adding a"
gra.add_vertex(Vertex(chr(a)))
if (b not in gra ):
print "adding b"
gra.add_vertex(Vertex(chr(b)))
You are trying to use not in, which tests for containment; implement the __contains__ hook to facilitate that:
def __contains__(self, vertex):
return vertex.name in self.vertices
I've assumed you wanted to test for vertices, so create one before testing for containment:
a = Vertex(chr(a))
if a not in gra:
print "adding a"
gra.add_vertex(a)
For iteration, I'd not make Graph itself the iterator; that limits you to iterating just once. Your next() method also lacks a return statement, so all you are doing is produce a sequence of None objects.
Make it an iterable instead, so return a new iterator object each time __iter__ is called. You can most simply achieve this by making __iter__ a generator:
def __iter__(self):
for vertex in self.vertices.itervalues():
yield vertex
Note the yield. I've assumed you wanted to iterate over the vertices.

How to query on a list by list comprehension and min/max functionalities

I have two Python classes: Agent and Group...
Each Group has a centerGroup property, plus a static list of groups, i.e. GroupList
Here is a brief overview of the Group class:
import Agent
class Group(object):
"""description of class"""
GroupIdentifier = 1
GroupThreshold = 10
GroupList = []
def __init__(self, agentList = None ,groupCenter = None, gruopIdentifier = None):
global GroupIdentifier
global GroupList
self.groupIdentifier = GroupIdentifier
Group.GroupIdentifier += 1
Group.GroupList.append(self)
self.groupCenter = groupCenter
self.agentList = agentList
Furthermore, within the Agent class, I am going to find the minimum euclidean distance of a typical agent from all centerGroup properties corresponding to the groups in the groupList... (There is an offset, is which GAMMA_TRESHOLD)...
One can depict the related part of Agent class, as below snippet:
import Group
class Agent(object):
"""description of class"""
GAMMA_TRESHOLD = 20
def __init__(self, point = None, groupId = None):
self.locationX = point.x
self.locationY = point.y
self.groupId = 0
def get_agent_distance_from_groupCenter(self, object):
return math.sqrt(math.pow(self.locationX - point.x, 2) +
math.pow(self.locationY - point.y, 2))
def gamma_condition(self):
#I KNOW THIS IMPLEMENTATION IS WRONG... JUST GOTTA SHOW THE TARGET!
return Group.Group.GroupList[Group.Group.GroupList.index(min(get_agent_distance_from_groupCenter(agent, group.groupCenter) - GAMMA_TRESHOLD))]
From a mathematical manner perspective, the problem is minimizing the below norm and introducing the group, which its centerGroup is nearest to the agent:
min \norm{centerGroup_{i} - agent - TRESHOLD}
Would you please helping me to write such query (valid processing for gamma_condition method) by list comprehension of Python?!
All in all, with due attention to lack of any better idea from the other people, my investigations lead to below solution for this problem:
def gamma_condition(self):
temp = []
maxValue = 0
temp = [[item.groupIdentifier, JOIN_TRESHOLD - self.get_agent_distance_from_groupCenter(item.groupCenter)] for item in Group.Group.GroupList]
for item in temp:
maxValue = max(float(i) for i in item[1])
if maxValue > 0:
index = temp.index(maxValue)
NearestGroupIdToJoin = temp[index][0]
return NearestGroupIdToJoin
else:
return None

Python - how to compare all items within list

As python starter, trying to get help from smart people when encountered the problem. And that is now:
I got to compare items (Qt scene items) from one list among each other, and make separate groups of items which collides mutually.
Please help me with code :
class MainWin(QMainWindow):
def __init__(self):
super(MainWin, self).__init__()
self.Win()
self.L = self.buildAllWalls()
items = self.scene.items()
allGroups = groupItemsFromList(None, items)
self.paintGroups(allGroups)
print len(allGroups)
def paintGroups(self, groups):
for g in groups :
color = QColor(0, 0, 0)
# RANDOM COLOR
namcol = "#%s" % "".join([hex(randrange(0, 255))[2:] for i in range(3)])
color.setNamedColor(namcol)
while color.isValid() == False : # ERROR CHECK
namcol = "#%s" % "".join([hex(randrange(0, 255))[2:] for i in range(3)])
color.setNamedColor(namcol)
pen = QPen(color, 14, Qt.SolidLine)
for w in g :
w.setPen(pen)
def Win(self):
self.scene = QGraphicsScene()
self.sView = QGraphicsView(self.scene)
self.sView.setRenderHint(QPainter.Antialiasing)
self.sView.setAlignment( Qt.AlignLeft | Qt.AlignTop )
self.setCentralWidget(self.sView)
self.setGeometry(20, 380, 400, 300)
self.show()
def buildAllWalls(self):
data = self.wallCoordinates()
for p in range(len(data)) :
ptA = QPointF(data[p][0], data[p][1])
ptB = QPointF(data[p][2], data[p][3])
self.wall(ptA, ptB)
def wall(self, ptA, ptB):
pen = QPen(QColor(100, 100, 100), 14, Qt.SolidLine)
currL = self.scene.addLine(QLineF(ptA.x(), ptA.y(), ptB.x(), ptB.y()))
currL.setPen(pen)
return currL
#[50,75,325,75],
def wallCoordinates(self):
data = [[50,100,150,100],[175,200,125,200],[175,275,125,275],[175,275,175,200],
[150,150,150,100],[175,100,225,100],[250,100,325,100],[350,125,175,125],
[50,125,125,125],[125,175,125,125],[150,150,175,150],[175,150,175,200],
[50,150,100,150],[100,150,100,200],[100,200,125,200],[50,175,75,175],
[75,225,75,175],[75,225,125,225],[125,275,125,225]]
return data
def main():
app = QApplication(sys.argv)
ex = MainWin()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Here is how I would write this:
def groupItemsFromList(self, itemList):
tmp = itemList[:]
allGroups = []
while tmp:
it = tmp.pop(0)
currentGroup = [it]
# loop from back to front so we can remove items safely
for i in range(len(tmp)-1, -1, -1):
if it.collidesWithItem(tmp[i]):
currentGroup.append(tmp.pop(i))
allGroups.append(currentGroup)
return allGroups
For example:
class Test(object):
def __init__(self, key):
self.key = key
def collidesWithItem(self, other):
return isinstance(other, self.__class__) and self.key == other.key
def __repr__(self):
return '{0}({1})'.format(self.__class__.__name__, self.key)
example = [Test(1), Test(2), Test(1), Test(1), Test(3), Test(2), Test(3), Test(4)]
print groupItemsFromList(None, example)
Output:
[[Test(1), Test(1), Test(1)], [Test(2), Test(2)], [Test(3), Test(3)], [Test(4)]]
This makes the assumption that all items that collide with an item will also collide with each other.
edit: Sounds like the assumption was not valid, try the following (untested):
def groupItemsFromList(self, itemList):
tmp = itemList[:]
allGroups = []
while tmp:
it = tmp.pop(0)
currentGroup = [it]
i = len(tmp) - 1
while i >= 0:
if any(x.collidesWithItem(tmp[i]) for x in currentGroup):
currentGroup.append(tmp.pop(i))
i = len(tmp) - 1
else:
i -= 1
allGroups.append(currentGroup)
return allGroups
It looks like you could do this:
def groupItemsFromList(self, itemList):
"""
Make a list of lists, where each list is composed of the
items (excepting itself, of course) that an item collides with.
"""
return [
[item for item in itemList[:i] + itemList[i:] if item.collidesWithItem(x)]
for i, x in enumerate(itemList)
]
itemList[:i] + itemList[i:] is python idiom for "I want all elements of the original list except the i'th item."
Later: I see. You want something more like this:
def groupItemsFromList(self, itemList):
def collision_indexes(i, target):
return [i] + [j for j, item in enumerate(itemList[i + 1:], start=i + 1) if item.collidesWithItem(target)]
processed = set()
results = []
for i, target in enumerate(itemList):
if i not in processed:
indexes = collision_indexes(i, target)
processed.update(indexes)
results.append([itemList[j] for j in indexes])
return results
The only advantage here is that this is side-effect-free code. There is no mutation to the original data but only functions applied to the data and changes made to new, temporary data structures.

Categories