Удалить то, что в одном списке из другого списка - PullRequest
0 голосов
/ 10 января 2019

У меня есть два списка, которые содержат несколько элементов одного типа:

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 голосов
/ 10 января 2019

Прежде всего, было бы неплохо следовать принципу «Не повторяйся» и написать функцию сравнения для будущего использования:


    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 ++ под названием параметры привязки , которая поможет нам здесь

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

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

И вот как вы удаляете специальные записи из списка.
0 голосов
/ 10 января 2019

Я думаю, что самый чистый путь будет:

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)
            }
        }
    }
}
0 голосов
/ 10 января 2019

Вы должны рассмотреть remove_if или erase_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
}

Ваш код затрудняет понимание вашей цели (по крайней мере, меня).

стереть и стереть_if

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...