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.
Related
I've noticed that the code prints the date twice to the constructor and am having trouble understanding why since I believe I only instantiate the object once within my code.
This is the constructor
def __init__(self):
self.today = date.today()
print(self.today)
Here is where I instantiate it
self.data = database()
self.schedule_today = self.data.get_bulletin()
Full code for this section of the program with some unfinished functions
class database:
sch_today = ['apt: 8:00', "breakfast", "music", 'apt: 9:00', "therapy", 'apt: 12:00', "lunch"]
test_schedule = []
def __init__(self):
self.today = date.today()
print(self.today)
def get_parse_bulletin_list(self):
temp = []
index = 0
for i in self.sch_today:
if i[0:3] == 'apt':
while index%3 != 0:
temp.append('')
index+=1
temp.append(i)
else:
temp.append(i)
index += 1
return temp
def get_bulletin(self):
n_count = 1
temp = []
ref = self.get_parse_bulletin_list()
for i in ref:
if i[0:3] == 'apt':
temp.append(paper_scrap().get_layout())
n_count = 1
elif not i:
temp.append(Notecard().blank_layout())
#elif i[0:5] == '[hlf]':
#temp.append(Notecard())
elif n_count >= 3: #allign left
temp.append(Notecard())
else:
temp.append(Notecard())
n_count += 1
return temp
def update_schedule(self):
with open('calendar.txt') as r:
pass
class BulletinInterface(RelativeLayout):
def __init__(self, **kwargs):
super(BulletinInterface, self).__init__(**kwargs)
self.data = database()
self.schedule_today = self.data.get_bulletin()
self.l1 = BulletinArea(size_hint=(1,1),
padding=(38, 135, 37, 34),
orientation=('tb-lr'))
self.add_widget(self.l1)
self.b1 = Button(text="test",
background_color=(1, 1, 1, 1),
size_hint=(0.1, 0.1)
)
self.b1.bind(on_press=self.bulletin_init)
self.add_widget(self.b1)
# bulletin board initialize
self.bulletin_init()
def bulletin_init(self, touch=None):
self.init_bulletin(self.schedule_today)
def init_bulletin(self, element_list):
for i in element_list:
self.l1.add_widget(i)
Found the problem after reviewing the construction of the GUI. The KV language and regular python code were both instantiating the GUI, leading to duplicate function calls for everything.
maybe a bit trivial question but i'm having trouble calling the object.
How can I call an object from this class and possibly call the add method correctly?
sample code:
class MyMatrix:
height = 0
width = 0
data = tuple()
def __init__(self, data):
self.height = len(data)
self.width = len(data[0])
self.data = data
def add(mat1, mat2):
if mat1.height != mat2.height or mat1.width != mat2.width:
print("The matrices are not the same size!")
return
rows = []
for i in range(len(mat1.data)):
row = []
for j in range(len(mat1.data[0])):
row.append(mat1[i][j] + mat2[i][j])
rows.append(tuple(row))
return MyMatrix(tuple(rows))
Thank you in advance for every answer.
You can call the methods like follows; for your code to work, however, you need to implement getitem (so that you can do matrix[1][2] e.g.).
class MyMatrix:
height = 0
width = 0
data = tuple()
def __init__(self, data):
self.height = len(data)
self.width = len(data[0])
self.data = data
def __getitem__(self, item):
return self.data.__getitem__(item)
def add(mat1, mat2):
if mat1.height != mat2.height or mat1.width != mat2.width:
print("The matrices are not the same size!")
return
rows = []
for i in range(len(mat1.data)):
row = []
for j in range(len(mat1.data[0])):
row.append(mat1[i][j] + mat2[i][j])
rows.append(tuple(row))
return MyMatrix(tuple(rows))
m1 = MyMatrix([[1,2,3]])
m2 = MyMatrix([[3,2,1]])
m12 = m1.add(m2)
print(m12.data)
I have a curses program on python and i have this fragment of class. I am running def control_chat(self, sel_chat) from another class. When messages (self.messages is list like ["message", id_of_msg]) are updating, inputbox's window cleans itself. But i clear all screen by entering emptu lines, not touching last 3 lines (in this last 3 lines my input box).
def input_validator(self, key):
if key == 10 or self.new_msg:
return 7
else:
return key
def get_msg(self):
while self.chatting:
win = curses.newwin(2, self.cols, self.lines-2, 0)
inp = curses.textpad.Textbox(win)
text = inp.edit(validate=self.input_validator)
if text != "":
self.vk.send_message(self.peer_id, text)
def chat_clear(self):
lines = self.lines - 3
for y in range(lines):
self.wprint(self.empity_line, y=y, x=0)
def control_chat(self, sel_chat):
self.sel_chat = sel_chat
self.peer_id = self.vk.id_to_peer_id(self.sel_chat)
self.input_thread = Thread(target=self.get_msg)
self.input_thread.start()
while self.chatting:
self.messages = self.vk.list_chat(self.peer_id)
self.draw_chat()
def draw_chat(self):
self.chat_clear()
self.top_bar_draw()
for message in self.messages:
name_line = str(message[1])
self.stdscr.attron(color_pair(1))
self.stdscr.addstr(name_line)
self.stdscr.attroff(color_pair(1))
self.stdscr.addstr(": "+message[0]+"\n")
self.wprint(self.screen_line, y=self.lines-3, x=0)
self.messages = []
# time.sleep()
def wprint(self, str, y=-1, x=-1):
if (y == -1) and (x == -1):
self.stdscr.addstr(str+"\n")
else:
self.stdscr.addstr(y, x, str+"\n")
self.stdscr.refresh()
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 made a functionality, but I not happy with the quantity of the code. The end result is good, but I believe it can be made much easier, only I don't know how.
The functionality: If equal items > 1 in list that all equal items getting unique set number. Below I made an unit test for the end result. I'm not happy with the class CreatSet. Can somebody advise me how this can be implemented better.
import unittest
class Curtain(object):
def __init__(self, type, fabric, number):
self.type = type
self.fabric = fabric
self.number = number
self.set_number = None
def __str__(self):
return '%s %s %s %s' % (self.number, self.type, self.fabric, self.set_name)
def __eq__(self, other):
return self.type == other.type and self.fabric == other.fabric
class CreatSet(object):
def make_unique(self, original_list):
checked = []
for e in original_list:
# If curtain: type and fabric is equal
if e not in checked:
checked.append(e)
return checked
def create_set(self, curtains):
# Uniuqe items in list
unique_list = self.make_unique(curtains)
result = []
for x in unique_list:
# Create set list
set_range = []
for y in curtains:
if y == x:
set_range.append(y)
# Add set range into list
result.append(set_range)
# Create set number
set_result = []
set_number = 0
for x in result:
if len(x) == 1:
set_result.append(x[0])
else:
set_number += 1
for y in x:
y.set_number = set_number
set_result.append(y)
# Return list ordered by number
return sorted(set_result, key=lambda curtain: curtain.number)
class TestCreateSet(unittest.TestCase):
def setUp(self):
self.curtains = []
self.curtains.append(Curtain('pleatcurtain', 'pattern', 0))
self.curtains.append(Curtain('pleatcurtain', 'plain', 1))
self.curtains.append(Curtain('pleatcurtain', 'pattern', 2))
self.curtains.append(Curtain('foldcurtain', 'pattern', 3))
self.curtains.append(Curtain('pleatcurtain', 'plain', 4))
self.curtains.append(Curtain('foldcurtain', 'plain', 5))
self.curtains.append(Curtain('pleatcurtain', 'pattern', 6))
self.curtains.append(Curtain('foldcurtain', 'pattern', 7))
def test_auto_set(self):
creat_set = CreatSet()
result = creat_set.create_set(self.curtains)
# Creating set
self.assertEqual(result[0].set_number, 1) # pleatcurtain, pattern
self.assertEqual(result[1].set_number, 2) # pleatcurtain, plain
self.assertEqual(result[2].set_number, 1) # pleatcurtain, pattern
self.assertEqual(result[3].set_number, 3) # foldcurtain, pattern
self.assertEqual(result[4].set_number, 2) # pleatcurtain, plain
self.assertEqual(result[5].set_number, None) # foldcurtain, plain
self.assertEqual(result[6].set_number, 1) # pleatcurtain, pattern
self.assertEqual(result[7].set_number, 3) # foldcurtain, pattern
if __name__ == '__main__':
unittest.main()