从另一个列表中删除一个列表中的内容

时间:2019-01-10 08:57:45

标签: c++ list iterator

我有两个列表,其中包含一堆相同类型的元素:

std::list<Part> allParts = step.getSubParts();
std::list<Part> toRemove;
for (Part part : allParts)
{
    for (Part partTwo : allParts) {
        if (part.getEdges() == partTwo.getEdges())
            if (part.getFaces() == partTwo.getFaces())
                if (part.getShells() == partTwo.getShells())
                    if (part.getVertices() == partTwo.getVertices())
                        if (part.getWires() == partTwo.getWires())
                        {
                            part.addAmount(1);
                            toRemove.push_back(partTwo);
                        }

    }
}

我尝试遍历两者并从中移除,但是我不断遇到list iterators are incompatible错误。这是我最近的尝试:

std::list<Part>::iterator it;
for (it = step.getSubParts().begin(); it != step.getSubParts().end();)
{
    std::list<Part>::iterator i;
    for (i = toRemove.begin(); i != toRemove.end();)
    {
        if (it->getEdges() == i->getEdges())
            if (it->getFaces() == i->getFaces())
                if (it->getShells() == i->getShells())
                    if (it->getVertices() == i->getVertices())
                        if (it->getWires() == i->getWires())
                        {
                            it = step.getSubParts().erase(it);
                        }
                        else
                        {
                            it++;
                        }
        i++;
    }
}

我尝试的所有方法均无效。正确的方法是什么?

3 个答案:

答案 0 :(得分:2)

您应该考虑使用remove_iferase_if而不是自己擦除,以免使iterator在循环中无效。

顺便说一句,您应该这样写谓词:

if (it->getEdges() == i->getEdges() &&
    it->getFaces() == i->getFaces() &&
    it->getShells() == i->getShells() &&
    it->getVertices() == i->getVertices() &&
    it->getWires() == i->getWires()) {
    // do something
}

您的代码使人们(至少对我)难以理解您的目的。

erase and erase_if

答案 1 :(得分:1)

首先,遵循不要重复自己的原则并编写比较函数以供将来使用是一个好主意:


    auto compare_parts = [](const Part& p1, const Part& p2) -> bool {
        return ( (p1.getEdges() == p2.getEdges())
             and (p1.getFaces() == p2.getFaces())
             and (p1.getShells() == p2.getShells())
             and (p1.getVertices() == p2.getVertices())
             and (p1.getWires() == p2.getWires()) );
    }

您将使用它重写第一个循环,然后看它看起来有多简单。

那么为什么不使用c ++内置方法使用我们编写的函数从列表中删除元素呢?这使用了c ++中称为binding parameters的新功能,可以在这里为我们提供帮助

    #include <functional>
    using namespace std::placeholders;

    for (auto&& badPart : toRemove) {
        auto isBad = std::bind(compare_parts, badPart, _1);
        step.getSubParts().remove_if(isBad);
    }

这就是从列表中删除特殊条目的方式。

答案 2 :(得分:0)

我认为最干净的方法是:

1。为类Part

实现相等运算符

您可以将其放在类的内部或外部,如果将其实现为外部函数,则看起来像这样

inline bool operator==(const Part& lhs, const Part& rhs) {
    return lhs.getEdges() == rhs.getEdges() &&
    lhs.getFaces() == rhs.getFaces() &&
    lhs.getShells() == rhs.getShells() &&
    lhs.getVertices() == rhs.getVertices() &&
    lhs.getWires() == rhs.getWires();
}

2。实现循环,我建议使用迭代器

这只是一种实现方式

if (allParts.size() > 1) {
    for(auto partIt = std::begin(allParts); partIt != std::end(allParts); partIt++) {
        for(auto partIt2 = std::next(partIt); partIt2 != std::end(allParts);) { // Manual increasing because we erase stuff
            if(*partIt == *partIt2) { // Previously implemented equility operator
                partIt->AddAmount(1);
                partIt2 = allParts.erase(partIt2); // If erase, use the returned iterator as your next `Part`
            } else {
                partIt2++; // Only increment if nothing was erased (when you erase iterators get invalidated)
            }
        }
    }
}