Home > Blockchain >  How would I go about comparing a vector with itself, and removing elements according to a comparison
How would I go about comparing a vector with itself, and removing elements according to a comparison

Time:01-19

I have a vector v, which I want to compare each, with every other element. For the sake of simplicity, in my example, the vector comprises of integers, and the comparison function is simply if (el1 == el2). As such, std::unique will not work, as my real list contains some data structure.

Below is an example of what I have tried so far, but it does not remove all duplicate elements as expected.

#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; 
}

To reiterate, std::unique or any variation thereof would not work here, as I am trying to get this to work with a vector of custom data structures, and a simply duplicate remover will not work in my actual program, hence the use of the user-defined comparitor. The ordering of removal does not matter, I am just aiming to get one of the compared elements to removed from v so that that specific element is not compared with anything else.

What I would expect is something like

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

But instead, I get

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

Any help or pointers (get it?) would be greatly appreciated!

CodePudding user response:

std::unique accepts a custom binary predicate. So, std::unique would work if you provided it with the custom function you already made.

#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; 
}

It also works if the type you provided has an implemented 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;
}

CodePudding user response:

If time complexity is not a huge deal for you, you can convert your vector to a set, then back to vector. The set will remove duplicates and you should be left with unique values.

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

I believe the syntax is so or quite similar.

EDIT: There was a comment about this being wrong. Set can be replaced with unordered_set to remove sorting effect, although I'm not certainly sure about vector->set->vector conversion, that needs to be checked. But still, you can loop through the set and construct vector by yourself if the conversion is not supported.

In summary, you should be able to do this:

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

If ordering matters, changing set<struct> to unordered_set<struct> shall work as far as I know.

  • Related