0

Python初心者として、問題が発生したときに賢い人から助けを得ようとしています. そしてそれは今です:

1 つのリストのアイテム (Qt シーン アイテム) を相互に比較し、相互に衝突するアイテムの個別のグループを作成する必要がありました。

コードで私を助けてください:

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()
4

2 に答える 2

1

これができるようです:

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:]「i番目のアイテムを除く元のリストのすべての要素が必要です。」のPythonイディオムです。


あと:なるほど。あなたはこのようなものがもっと欲しい:

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

ここでの唯一の利点は、これが副作用のないコードであることです。元のデータへの変更はありませんが、データに適用される機能と、新しい一時的なデータ構造への変更のみが行われます。

于 2013-04-16T17:34:03.997 に答える
1

これが私がこれを書く方法です:

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

例えば:

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)

出力:

[[Test(1), Test(1), Test(1)], [Test(2), Test(2)], [Test(3), Test(3)], [Test(4)]]

これは、アイテムと衝突するすべてのアイテムが互いに衝突することを前提としています。

編集:仮定が有効ではなかったように聞こえます。次のことを試してください(テストされていません):

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
于 2013-04-16T17:32:26.093 に答える