我有一个班级:
// https://github.com/KubaO/stackoverflown/tree/master/questions/scene-polygon-7727656
#include <QtWidgets>
class MainWindow : public QWidget
{
Q_OBJECT
QGridLayout m_layout{this};
QPushButton m_new{"New"};
QPushButton m_erase{"Erase All"};
QLabel m_label;
QGraphicsView m_view;
public:
MainWindow() {
m_layout.addWidget(&m_new, 0, 0);
m_layout.addWidget(&m_erase, 0, 1);
m_layout.addWidget(&m_label, 0, 2);
m_layout.addWidget(&m_view, 1, 0, 1, 3);
m_view.setBackgroundBrush(Qt::black);
m_view.setAlignment(Qt::AlignBottom | Qt::AlignLeft);
m_view.scale(1, -1);
connect(&m_new, &QPushButton::clicked, this, &MainWindow::newItem);
connect(&m_erase, &QPushButton::clicked, this, &MainWindow::clearScene);
}
void setScene(QGraphicsScene * scene) {
m_view.setScene(scene);
}
Q_SIGNAL void newItem();
Q_SIGNAL void clearScene();
Q_SLOT void setText(const QString & text) { m_label.setText(text); }
};
class MyScene : public QGraphicsScene {
Q_OBJECT
public:
struct Status {
int paths;
int elements;
};
private:
bool m_newItem = {};
Status m_status = {0, 0};
QPainterPath m_path;
QGraphicsPathItem m_pathItem;
QGraphicsLineItem m_lineItem;
struct PathUpdater {
Q_DISABLE_COPY(PathUpdater)
MyScene & s;
PathUpdater(MyScene & scene) : s(scene) {
s.m_pathItem.setPath({}); // avoid a copy-on-write
}
~PathUpdater() {
s.m_pathItem.setPath(s.m_path);
s.m_status = {0, s.m_path.elementCount()};
for (auto i = 0; i < s.m_status.elements; ++i) {
auto element = s.m_path.elementAt(i);
if (element.type == QPainterPath::MoveToElement)
s.m_status.paths++;
}
emit s.statusChanged(s.m_status);
}
};
void mousePressEvent(QGraphicsSceneMouseEvent *event) override {
PathUpdater updater(*this);
auto pos = event->scenePos();
m_lineItem.setLine(0, 0, pos.x(), pos.y());
m_lineItem.setVisible(true);
if (m_path.elementCount() == 0 || m_newItem)
m_path.moveTo(pos);
m_path.lineTo(pos.x()+1,pos.y()+1); // otherwise lineTo is a NOP
m_newItem = {};
}
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override {
PathUpdater updater(*this);
auto pos = event->scenePos();
m_lineItem.setLine(0, 0, pos.x(), pos.y());
m_path.setElementPositionAt(m_path.elementCount()-1, pos.x(), pos.y());
}
void mouseReleaseEvent(QGraphicsSceneMouseEvent *) override {
m_lineItem.setVisible(false);
}
public:
MyScene() {
addItem(&m_pathItem);
addItem(&m_lineItem);
m_pathItem.setPen({Qt::red});
m_pathItem.setBrush(Qt::NoBrush);
m_lineItem.setPen({Qt::white});
m_lineItem.setVisible(false);
}
Q_SLOT void clear() {
PathUpdater updater(*this);
m_path = {};
}
Q_SLOT void newItem() {
m_newItem = true;
}
Q_SIGNAL void statusChanged(const MyScene::Status &);
Status status() const { return m_status; }
};
int main(int argc, char *argv[])
{
using Q = QObject;
QApplication app{argc, argv};
MainWindow w;
MyScene scene;
w.setMinimumSize(600, 600);
w.setScene(&scene);
Q::connect(&w, &MainWindow::clearScene, &scene, &MyScene::clear);
Q::connect(&w, &MainWindow::newItem, &scene, &MyScene::newItem);
auto onStatus = [&](const MyScene::Status & s){
w.setText(QStringLiteral("Paths: %1 Elements: %2").arg(s.paths).arg(s.elements));
};
Q::connect(&scene, &MyScene::statusChanged, onStatus);
onStatus(scene.status());
w.show();
return app.exec();
}
#include "main.moc"
我还有一个包含此类的多个实例的列表,例如:
class ex(object):
def __init__(self, tag, quantity):
self.tag = tag
self.quantity = quantity
如果self.tag与列表中的另一个实例匹配,我试图想出一个添加self.quantiy属性的好方法。
输出将是:
[ex('a', 10.5), ex('b', 5.0), ex('c', 2.0), ex('a', 5.0), ex('c', -10.0)]
感谢
编辑:最终实例可以是新实例或累积的第一个列表。列表的最大大小约为len()1000
答案 0 :(得分:2)
O(n^2)
,但代码更简单。
class ex(object):
def __init__(self, tag, quantity):
self.tag = tag
self.quantity = quantity
def __repr__(self):
return '%s(%r, %r)' % (self.__class__.__name__, self.tag, self.quantity)
exes = [ex('a', 10.5), ex('b', 5.0), ex('c', 2.0), ex('a', 5.0), ex('c', -10.0)]
summed_exes = [ex(tag, sum(e.quantity for e in exes if e.tag == tag))
for tag in sorted({e.tag for e in exes})]
print(summed_exes)
sorted
是可选的。
输出:
[ex('a', 15.5), ex('b', 5.0), ex('c', -8.0)]
答案 1 :(得分:1)
我认为一个普通的循环实际上比这里的列表理解更好。通过跟踪已经看到的标签,可以实现O(n)的复杂性:
seen = {}
for instance in in_list:
try:
existing = seen[instance.tag]
except KeyError:
seen[instance.tag] = instance
else:
existing.quantity += instance.quantity
out_list = list(seen.values()) # can drop the "list" call on Python 2.x
将使用每个组中的第一个实例,如果再次看到该标记,则会在之后更新。
如果您希望保留代码的原始排序,请为collections.OrderedDict
变量而不是普通字典输入seen
。将会有轻微的性能损失,但解决方案仍然是O(n)复杂性。
答案 2 :(得分:1)
这是一个创建新对象的O(n)解决方案:
In [9]: class Ex(object):
...: def __init__(self, tag, quantity):
...: self.tag = tag
...: self.quantity = quantity
...:
...: def __repr__(self):
...: return '%s(%r, %r)' % (self.__class__.__name__, self.tag, self.quantity)
...:
In [10]: objs = [Ex('a', 10.5), Ex('b', 5.0), Ex('c', 2.0), Ex('a', 5.0), Ex('c', -10.0)]
In [11]: objs
Out[11]: [Ex('a', 10.5), Ex('b', 5.0), Ex('c', 2.0), Ex('a', 5.0), Ex('c', -10.0)]
In [12]: grouped = {}
In [13]: for obj in objs:
...: grouped[obj.tag] = grouped.get(obj.tag, 0) + obj.quantity
...:
In [14]: new_objs = [Ex(k, v) for k,v in grouped.items()]
In [15]: new_objs
Out[15]: [Ex('b', 5.0), Ex('a', 15.5), Ex('c', -8.0)]
如果订单有问题,您可以使用defaultdict
或Counter
或OrderedDict
来获得更高的效果。