我将如何将向量与自身进行比较,并根据比较函数删除元素?

How would I go about comparing a vector with itself, and removing elements according to a comparison function?

提问人:P. H. Allus 提问时间:1/19/2023 最后编辑:P. H. Allus 更新时间:1/19/2023 访问量:83

问:

我有一个向量,我想将每个向量与其他所有元素进行比较。为了简单起见,在我的示例中,向量由整数组成,比较函数简单为 。因此,将不起作用,因为我的真实列表包含一些数据结构。vif (el1 == el2)std::unique

下面是我到目前为止尝试过的示例,但它并没有像预期的那样删除所有重复的元素。

#include <iostream> 
#include <vector> 
#include <algorithm> 

bool CompareElements(int el1, int el2)
{
    if (el1 == el2) { // Just as an example
        return true;
    } else {
        return false;  
    }
}

int main() 
{ 
    std::vector<int> v = {4, 1, 3, 2, 2, 3, 6, 2, 3, 1, 4, 3, 2, 3, 5, 6, 5}; 

    // Should remove el1 if CompareElements() returns true.
    v.erase( 
        std::remove_if(v.begin(), v.end(), [&](int el1)
        { 
            bool result = false;
            std::for_each(v.begin(), v.end(), [&](int el2) 
            {   
                result = CompareElements(el1, el2);
            });
            return result;
        }), 
        v.end()
    );

    // Print the contents of v
    std::cout << "v = {";
    for (auto el : v) 
       std::cout << el << ", ";
    std::cout << "}\n"; 

    return 0; 
}

重申一下,或其任何变体在这里都行不通,因为我正试图让它与自定义数据结构的向量一起使用,而简单的重复去除器在我的实际程序中不起作用,因此使用用户定义的比较器。删除的顺序无关紧要,我只是想从中删除其中一个比较元素,以便该特定元素不会与其他任何元素进行比较。std::uniquev

我所期望的是这样的

v = {1, 4, 2, 3, 6, 5}

但相反,我得到了

v = {4, 1, 3, 2, 2, 3, 6, 2, 3, 1, 4, 3, 2, 3, 6, }

任何帮助或指示(明白了吗?)将不胜感激!

C++ 循环 std stdvector

评论

0赞 bolov 1/19/2023
std::unqiue 使用自定义谓词,因此您可以使用它。
0赞 Quimby 1/19/2023
每个循环的目的是什么?您只是覆盖,因此仅有效地与最后一个元素进行比较。你是故意的吗?但是,迭代主动更改的序列也是一个很大的禁忌。result|=

答:

0赞 Rhidian12 1/19/2023 #1

std::unique 接受自定义二进制谓词。因此,如果您为它提供您已经创建的自定义函数,std::unique 将起作用。

#include <iostream> 
#include <vector> 
#include <algorithm> 

int main() 
{ 
    std::vector<int> v = {4, 1, 3, 2, 2, 3, 6, 2, 3, 1, 4, 3, 2, 3, 5, 6, 5}; 
    v.erase(std::unique(v.begin(), v.end(), [](const int a, const int b)
        {
            return a == b;
        }), v.end());

    // Print the contents of v
    std::cout << "v = {";
    for (auto el : v) 
       std::cout << el << ", ";
    std::cout << "}\n"; 

    return 0; 
}

如果您提供的类型具有实现的 .operator==

struct Data
{
    Data(int _param)
        : m_Data{_param}
    {}

    int m_Data{};
    
    bool operator==(const Data& other) const
    {
        return m_Data == other.m_Data;
    }
};

int main()
{
    std::vector<Data> a{ 0,1,1,1,2,3,4,5 };

    a.erase(std::unique(a.begin(), a.end()), a.end());

    for (auto i : a)
        std::cout << i.m_Data << ", ";

    return 0;
}
0赞 Alexsen 1/19/2023 #2

如果时间复杂度对你来说不是什么大问题,你可以将向量转换为集合,然后再转换回向量。该集将删除重复项,您应该保留唯一值。

v=vector<struct>(set<struct>(v.begin(), v.end()));

我相信语法是如此或非常相似。

编辑:有人评论说这是错误的。Set 可以替换为 unordered_set 以消除排序效果,尽管我不确定需要检查的向量->集>向量转换。但是,如果不支持转换,您仍然可以自己遍历集合并构造向量。

总之,您应该能够做到这一点:

set<struct> st=set<struct>(v.begin(), v.end());
vector<struct> uniqvec=vector<struct>(st.begin(), st.end())

如果排序很重要,据我所知,更改为应该有效。set<struct>unordered_set<struct>

评论

1赞 NathanOliver 1/19/2023
你不能从这样的向量中构造一个向量。你必须这样做set{ set<struct> s(v.begin(), v.end()); v = vector<struct>(s.begin(), s.end()); }
0赞 Alexsen 1/19/2023
@NathanOliver 没错,我只是不想删除我的错误,不要把正确性归咎于我。无论哪种方式,逻辑都应该有效并且可能会有所帮助,尽管语法在这里和那里发生了一些变化。