Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare two vectors for equality?

Tags:

c++

algorithm

stl

I have the following program:

std::vector<int> nums = {1, 2, 3, 4, 5};
std::vector<int> nums2 = {5, 4, 3, 2, 1};

bool equal = std::equal(nums.begin(), nums.end(), nums2.begin());
if (equal)
{
    cout << "Both vectors are equal" << endl;
}

There are two vectors that have equal elements. std::equal function does not work here because it goes sequentially and compares corresponding elements. Is there a way to check that both these vectors are equal and get true in my case without sorting? In real example I do not have integers but custom objects which comparing as equality of pointers.

like image 421
Oleg Avatar asked Feb 21 '21 11:02

Oleg


Video Answer


2 Answers

You can construct a std::unordered_set from each vector, then compare those, as shown in the code snippet below:

#include <iostream>  
#include <vector>  
#include <unordered_set> 

using namespace std;

int main()
{
    std::vector<int> nums = { 1, 2, 3, 4, 5 };
    std::vector<int> nums2 = { 5, 4, 3, 2, 1 };
    std::vector<int> nums3 = { 5, 4, 9, 2, 1 };

    std::unordered_set<int> s1(nums.begin(), nums.end());
    std::unordered_set<int> s2(nums2.begin(), nums2.end());
    std::unordered_set<int> s3(nums3.begin(), nums3.end());

    if (s1 == s2) {
        std::cout << "1 and 2 are equal";
    }
    else {
        std::cout << "1 and 2 are different";
    }
    std::cout << std::endl;

    if (s1 == s3) {
        std::cout << "1 and 3 are equal";
    }
    else {
        std::cout << "1 and 3 are different";
    }
    std::cout << std::endl;

    return 0;
}

However, there are some points to bear in mind:

  1. For vectors of custom type objects, you would need to provide an operator== for that type (but that would have to be done anyway, or how can you say if the two vectors have the same contents).
  2. Vectors that containing duplicate entries will create sets that have those duplicates removed: Thus, {1, 2, 2, 3} will show equal to {1, 2, 3}.
  3. You will also need to provide a std:hash for your custom type. For a trivial class, bob, which just wraps an integer, that hash, and the required operator==, could be defined as shown below; you can then replace the <int> specializations in the above example with <bob> and it will work. (This cppreference article explains more about the hash.)
class bob {
public:
    int data;
    bob(int arg) : data{ arg } { }
};
bool operator==(const bob& lhs, const bob& rhs)
{
    return lhs.data == rhs.data;
}
template<> struct std::hash<bob> {
    std::size_t operator()(bob const& b) const noexcept {
        return static_cast<size_t>(b.data);
    }
};
like image 123
Adrian Mole Avatar answered Oct 12 '22 05:10

Adrian Mole


The std::is_permutation standard library algorithm does exactly what you want. It returns true if both ranges contain the same elements in any order.

It might be slow for some applications but it only requires equality comparison and it doesn't require a temporary container or additional memory allocation.

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

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

    bool equal = std::is_permutation(nums.begin(), nums.end(), nums2.begin(), nums2.end());

    if (equal) {
        std::cout << "Both vectors are equal" << std::endl;
    }
}
like image 2
Blastfurnace Avatar answered Oct 12 '22 06:10

Blastfurnace