简体   繁体   中英

C++/STL which algorithm should I use to check if a container has duplicates?

Is there any STL algorithm that would tell if a container has duplicated elements (using the operator== or a given predicate)?

Let's consider those two vectors:

std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 1, 2, 1 };

I would expect a function like that:

std::is_exclusive( v1.begin(), v1.end() ); // returning true
std::is_exclusive( v2.begin(), v2.end() ); // returning false

Is there such a simple function? I could not find any (found std::unique , but this modifies the vector...)

Note: I'm not asking how to "check if a container has duplicates", I know how I can do that (basically, I can do ( std::set<int>( v1.begin(), v1.end() ).size() == v1.size() ) and there may exist many other options. I'm asking if there is a STL algorithm function that would do it in a smarter way because I'm surprised I could not find any...

One way of implementing your STL-like is_exclusive template function would be by using a std::unordered_map which keeps the counting of the elements in the range. The function template could return false as soon as the count for any element is over one:

#include <unordered_map>

template<typename ForwardIt>
bool is_exclusive(ForwardIt first, ForwardIt last) {
    std::unordered_map<typename ForwardIt::value_type, unsigned> count;

    for (auto it = first; it != last; ++it)
        if (++count[*it] > 1)
            return false;

    return true;
}

For your example:

int main() {
    std::vector<int> v1{ 1, 2, 3 };
    std::vector<int> v2{ 1, 2, 1 };


    assert(is_exclusive(v1.begin(), v1.end()));
    assert(!is_exclusive(v2.begin(), v2.end()));
}

The only thing I can thing is https://en.cppreference.com/w/cpp/algorithm/adjacent_find , but it requires that the elements are sorted as it will check in the adjacent element.

EDIT:

There is no stl algorithm that can do that as you ask, the other alternative is use std::any_of.

STL is about efficiency and universality. There seems to be no universal and efficient way to check if a container has duplicates without modifying it. Hence, no wonder that no such algorithm exists in STL.

One way of doing this is to use std::set.

Copy your vector into the set and compare if the number of elements are the same.

If yes you have no duplicate, if no you can guess the number of duplicates.

#include <iostream>
#include <iterator>
#include <vector>
#include <set>
int has_duplicate(const std::vector<int> & v)
{
    std::set<int> s(v.begin(), v.end());
    return v.size() - s.size();
}

int
main()
{

    std::vector<int> v1{ 1, 2, 3 };
    std::vector<int> v2{ 1, 2, 1 };
    std::cout << has_duplicate(v1) << std::endl;
    std::cout << has_duplicate(v2) << std::endl;
}

for v1 the output is 0 -> you have no duplicate for v2 the output is 1 -> you have one duplicate

The algorithm costs O(N*log(N))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM