【问题标题】:C++ - Appending one Vector to another, with removal of duplicates?C++ - 将一个向量附加到另一个向量,并删除重复项?
【发布时间】:2022-03-08 21:15:11
【问题描述】:

我想将一个向量 (vectorAlpha) 附加到另一个向量 (vectorBeta) 的末尾。我能想到两种不同的方法,我想知道如何分别做。

第一种方法是附加第二个向量并从新向量中删除所有重复项。另一种方法是在单个向量中单独保留重复项,但如果它们已经存在于 vectorALpha 中,则不要添加来自 vectorBeta 的任何项。

例如,如果向量是具有以下值的向量:

向量Alpha:

First line of alpha
An alpha line
An alpha line
Some line
Alpha fifth line

vectorBeta:

Beta first line
A beta line
A beta line
Some line
Beta fifth line

我认为第一种方法会产生组合向量:

First line of alpha
An alpha line
Some line
Alpha fifth line
Beta first line
A beta line
Beta fifth line

虽然第二种方法只是将两个数组组合在一起,但没有添加第二个向量中的“Some line”:

First line of alpha
An alpha line
An alpha line
Some line
Alpha fifth line
Beta first line
A beta line
A beta line
Beta fifth line

这两种方法使用的 C++ 代码是什么?

【问题讨论】:

    标签: c++ vector


    【解决方案1】:

    因为很明显

    1. 您只希望重复项从 vecB 中删除条目(如果它们存在于 vecA 中),而不是一般重复项
    2. 您想保留顺序

    答案应该(显然?)是 std::remove_copy_if。这么称呼它:

    #include <vector>
    #include <algorithm>
    
    typedef std::vector<int> Vec;
    struct Contained
    {
        const Vec& _sequence;
        Contained(const Vec &vec) : _sequence(vec) {}
        bool operator()(int i) const 
        { 
            return _sequence.end() != std::find(_sequence.begin(), _sequence.end(), i);
        }
    };
    
    int main()
    {
        Vec vecA;
        Vec vecB;
    
        std::remove_copy_if(vecB.begin(), vecB.end(), back_inserter(vecA), Contained(vecA));
    }
    

    您可能希望根据 vecA 的大小和性质优化谓词:

    #include <set>
    
    template <typename T>
    struct Contained
    {
        const std::set<T> _set;
        template <typename It> Contained(const It& begin, const It& end) : _set(begin, end) {}
        bool operator()(const T& i) const 
        { 
            return _set.end() != _set.find(i);
        }
    };
    

    将用作Contained&lt;int&gt;(vecA.begin(), vecA.end())。完整代码is compiling on codepad.org

    干杯

    【讨论】:

    • 一个非常优雅的问题解决方案!
    【解决方案2】:

    更新:新的answer here due to changed/added requirements

    typedef std::...<...> Vec;
    Vec vecA;
    Vec vecB;
    
    // fill your data
    
    // sort
    std::sort(vecA.begin(), vecA.end());
    std::sort(vecB.begin(), vecB.end());
    
    
    // join
    size_t mergesize = vecA.size();
    
    std::copy(vecB.begin(), vecB.end(), std::back_inserter(vecA));
    
    // merge
    std::inplace_merge(vecA.begin(), vecA.begin()+mergesize, vecA.end());
    

    您可以按如下方式组合加入+合并步骤

    Vec vecC;
    std::merge(vecA.begin(), vecA.end(),
                vecB.begin(), vecB.end(),
                std::back_insterter(vecC));
    

    作为最后一步,删除重复项:

    Vec::iterator pte = std::unique(vecC.begin(), vecC.end());
    // dups now in [pte, vecC.end()), so optionally erase:
    vecC.erase(pte, vecC.end());
    

    【讨论】:

    • 谢谢。对于 std::inplace_merge 行,我收到错误消息:“表达式:向量迭代器不兼容”?如果已经使用了 std::copy...backinserter() 行,为什么还需要这一行? vecC merge() 仅在对 vecA 和 vecB 进行排序时才有效,并且我不希望它们排序,我希望顺序保持不变 - 只需附加 vecB。同样对于删除重复项,如果已经在第一个向量中,我希望选择不添加第二个向量中的项目,而是保留任何其他重复项(如我上面的示例 - 两个向量都有重复项)。
    • 它确实为我编译:see codepad。您需要排序才能使用 unique 删除重复项。如果订单无关紧要,我建议使用 std::set (将更新答案)。稍后我将在单独的答案中解决您修改后的问题
    • 我已经在我的新答案here中回答了您改进后的问题@
    • 它可以编译,但std::copy 使mergepoint 迭代器无效。运行第一个代码段时,我收到断言失败,并显示消息“范围内的向量迭代器来自不同的容器”我怀疑这是由于复制期间向量被放大(尽管我之前试图通过保留来防止这种情况),或者来自mergepoint 迭代器,它不指向插入元素之前的位置,而是插入到插入元素的位置。我使用的解决方法是在复制之前存储矢量大小,然后使用 vecA.begin()+sizeBefore 而不是 mergepoint
    • 修复了我之前在答案中的评论中提到的问题。关于迭代器失效,另见en.cppreference.com/w/cpp/container#Iterator_invalidation
    【解决方案3】:

    两个向量中元素的顺序重要吗?如果没有,那么您可能应该改用集合。

    【讨论】:

    • 是的,顺序很重要。我希望元素保持原来的顺序。另外我认为集合不允许任何重复,我确实想要保留重复的选项。
    猜你喜欢
    • 2018-10-02
    • 1970-01-01
    • 2016-07-08
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    • 2013-03-06
    • 1970-01-01
    • 2020-08-03
    相关资源
    最近更新 更多