Counting struct elements in 2D vector C++ - c++

I have a 2D vector of structures of this type
typedef struct box
{
int boxVal;
char boxTakenBy;
} box;
I have myvector defined as:
vector<vector<box> > myvector(10,vector<box>(10))
My goal is to count number of elements with boxTakenBy == 'X'. I tried:
int mycount = std::count_if( myvector.begin(), myvector.end(),
[](const box &p ) { return p.boxTakenBy == 'X'; });
I am getting compilation error :
no match for call to ‘<lambda(const box&)>) (std::vector<box >&)
Not sure if my approach is wrong or just the syntax. Please correct if you find any syntax issue or suggest if any better approach is out there.

As mentioned by hauron elements of myvector are not boxes but vector<box>s. So what you need to do it iterate over 2 dimensions of myvector.
You can combine std::accumulate (to accumulate the sum) and std::count_if (to count the inner elements satisfying your condition ( == 'X') to achieve that like so:
#include <vector>
#include <algorithm>
#include <iostream>
#include <numeric>
struct box
{
int boxVal;
char boxTakenBy;
};
int main(){
using namespace std;
vector<vector<box> > myvector(10, vector<box>(10));
myvector[0][0].boxTakenBy = 'X';
myvector[2][0].boxTakenBy = 'X';
myvector[2][7].boxTakenBy = 'X';
myvector[5][7].boxTakenBy = 's';
int total_count = std::accumulate(myvector.begin(), myvector.end(), 0,
[](int acc, const vector<box>& curr)
{
return acc + std::count_if(curr.begin(), curr.end(),
[](const box& b ) { return b.boxTakenBy == 'X'; });
}
);
std::cout << total_count << '\n';
}
LIVE DEMO

You have two levels of vectors, so you need to traverse both.
You can use count_if to count the elements in each "inner" vector, then sum the results with accumulate:
int count = std::accumulate(myvector.begin(),
myvector.end(),
0,
[](int i, const vector<box>& bs)
{ return i + std::count_if(bs.begin(),
bs.end(),
[](const box& b)
{ return b.boxTakenBy == 'X';}); });
or, pulling out the innermost function and abstracting out the character:
auto takenBy = [](char c) { return [=](const box& b) { return b.boxTakenBy == c; };};
int count = std::accumulate(myvector.begin(),
myvector.end(),
0,
[&](int i, const vector<box>& bs)
{ return i + std::count_if(bs.begin(),
bs.end(),
takenBy('X')); });

Another solution can be to use std::for_each and std::count_if as following:
int mycount;
std::for_each( myvector.begin(), myvector.end(),
[&mycount](std::vector<box> const &p )
{ mycount += std::count_if(p.begin(),p.end(),[](box const & q){return q.boxTakenBy == 'X'; });
});

Standard library algorithms are great and everything but sometimes I think a ranged-based for loop is simpler:
auto mycount = 0;
for(const auto& row : myvector)
for(auto& item: row)
if (item.boxTakenBy == 'X') ++mycount;
Live demo.

Related

How can I convert std::vector<T> to a vector of pairs std::vector<std::pair<T,T>> using an STL algorithm?

I have a vector of integers:
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
Given that values.size() will always be even.
I simply want to convert the adjacent elements into a pair, like this:
std::vector<std::pair<int,int>> values = { {1,2}, {3,4} , {5,6}, {7,8} ,{9,10} };
I.e., the two adjacent elements are joined into a pair.
What STL algorithm can I use to easily achieve this? Is it possible to achieve this through some standard algorithms?
Of course, I can easily write an old school indexed for loop to achieve that. But I want to know what the simplest solution could look like using rangebased for loops or any other STL algorithm, like std::transform, etc.
Once we have C++23's extension to <ranges>, you can get most of the way there with std::ranges::views::chunk, although that produces subranges, not pairs.
#include <iostream>
#include <ranges>
#include <vector>
int main()
{
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
auto chunk_to_pair = [](auto chunk)
{
return std::pair(*chunk.begin(), *std::next(chunk.begin()));
};
for (auto [first, second] : values | std::ranges::views::chunk(2) | std::ranges::views::transform(chunk_to_pair))
{
std::cout << first << second << std::endl;
}
}
Alternatively, you could achieve a similar result by ziping a pair of strided views
#include <iostream>
#include <ranges>
#include <vector>
int main()
{
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
auto odds = values | std::ranges::views::drop(0) | std::ranges::views::stride(2);
auto evens = values | std::ranges::views::drop(1) | std::ranges::views::stride(2);
for (auto [first, second] : std::ranges::views::zip(odds, evens))
{
std::cout << first << second << std::endl;
}
}
That last one can be generalised to n-tuples
template <size_t N>
struct tuple_chunk_t
{
template <typename R, size_t... Is>
auto impl(R && r, std::index_sequence<Is...>)
{
using namespace ranges::view;
return zip(r | drop(Is) | stride(N)...);
}
template <typename R>
auto operator()(R && r) const
{
return impl(std::forward<R>(r), std::make_index_sequence<N>{});
}
template <typename R>
friend auto operator|(R && r, chunk_t)
{
return impl(std::forward<R>(r), std::make_index_sequence<N>{});
}
};
template <size_t N>
constexpr tuple_chunk_t<N> tuple_chunk;
I'm not sure why you would require a standard algorithm when writing it yourself is roughly 5 lines of code (plus boilerplate):
template<class T>
std::vector<std::pair<T, T>> group_pairs(const std::vector<T>& values)
{
assert(values.size() % 2 == 0);
auto output = std::vector<std::pair<T, T>>();
output.reserve(values.size()/2);
for(size_t i = 0; i < values.size(); i+=2)
output.emplace_back(values[i], values[i+1]);
return output;
}
And call it like so:
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
auto result = group_pairs(values)
Live Demo
I am not aware of a standard algorithm that does what you want directly (though I am not very familiar with C++20 and beyond). You can always write a loop and most loops can be expressed via std::for_each which is a standard algorithm.
As you are accumulating elements in pairs, I would give std::accumulate a try:
#include <vector>
#include <numeric>
#include <iostream>
struct pair_accumulator {
std::vector<std::pair<int,int>> result;
int temp = 0;
bool set = false;
pair_accumulator& operator+(int x){
if (set) {
result.push_back({temp,x});
set = false;
} else {
temp = x;
set = true;
}
return *this;
}
};
int main() {
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
auto x = std::accumulate(values.begin(),values.end(),pair_accumulator{}).result;
for (const auto& e : x) {
std::cout << e.first << " " << e.second << "\n";
}
}
Whether this is simpler than writing a plain loop is questionable admittedly.
If possible I would try to not transform the vector. Instead of accessing result[i].first you can as well use values[i*2] and similar for second. If this is not feasible the next option is to populate a std::vector<std::pair<int,int>> from the start so you don't have to do the transformation. For the first, depending on what you need in details, the following might be a start:
#include <vector>
#include <iostream>
struct view_as_pairs {
std::vector<int>& values;
struct proxy {
std::vector<int>::iterator it;
int& first() { return *it;}
int& second() { return *(it +1); }
};
proxy operator[](size_t index){
return proxy{values.begin() + index*2};
}
size_t size() { return values.size() / 2;}
};
int main() {
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
view_as_pairs v{values};
for (size_t i=0; i < v.size(); ++i){
std::cout << v[i].first() << " " << v[i].second() << "\n";
}
}
TL;DR: Consider if you can avoid the transformation. If you cannot avoid it, it is probably cleanest to write a loop. Standard algorithms help often but not always.
OK, I hinted in the comments about using std::adjacent_find, so here is how you would do this.
And yes, many (even myself) considers this a hack, where we are using a tool meant for something else to make short work of solving a seemingly unrelated problem:
#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>
int main()
{
//Test data
std::vector<int> v = {1,2,3,4,5,6,7,8,9,10};
// results
std::vector<std::pair<int,int>> result;
// save flag
bool save_it = true;
// Use std::adjacent_find
std::adjacent_find(v.begin(), v.end(), [&](int n1, int n2)
{ if (save_it) result.push_back({n1,n2}); save_it = !save_it; return false; });
for (auto& pr : result)
std::cout << pr.first << " " << pr.second << "\n";
}
Output:
1 2
3 4
5 6
7 8
9 10
The way it works is we ignore the second, fourth, sixth, etc. pairs, and only save the first, third, fifth, etc. pairs. That's controlled by a boolean flag variable, save_it.
Note that since we want to process all pairs, the std::adjacent_find predicate always returns false. That's the hackish part of this solution.
The solutions so far try to use the std::vector iterators as input to the algorithms directly. How about defining a custom iterator that returns a std::pair and has strides of 2? Creating the vector of pairs is then a one-liner that uses std::copy. The iterator effectively provides a "view" onto the original vector in terms of pairs. This also allows the use of many of the standard algorithms. The following example could also be generalized quite a bit to work with most container iterators, i.e. you do the difficult work of defining such an iterator once and then you can apply it to all sorts of containers and algorithms. Live example: https://godbolt.org/z/ceEsvKhzd
#include <vector>
#include <algorithm>
#include <iostream>
#include <cassert>
struct pair_iterator {
using difference_type = std::vector<int>::const_iterator::difference_type;
using value_type = std::pair<int, int>;
using pointer = value_type*;
using reference = value_type; // Not a pair&, but that is ok for LegacyIterator
// Can't be forward_iterator_tag because "reference" is not a pair&
using iterator_category = std::input_iterator_tag;
reference operator*()const { return {*base_iter, *(base_iter + 1)}; }
pair_iterator & operator++() { base_iter += 2; return *this; }
pair_iterator operator++(int) { auto ret = *this; ++(*this); return ret; }
friend bool operator==(pair_iterator lhs, pair_iterator rhs){
return lhs.base_iter == rhs.base_iter;
}
friend bool operator!=(pair_iterator lhs, pair_iterator rhs){
return lhs.base_iter != rhs.base_iter;
}
std::vector<int>::const_iterator base_iter{};
};
auto pair_begin(std::vector<int> const & v){ assert(v.size()%2==0); return pair_iterator{v.begin()}; }
auto pair_end(std::vector<int> const & v){ assert(v.size()%2==0); return pair_iterator{v.end()}; }
int main()
{
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
std::vector<std::pair<int, int>> pair_values;
std::copy(pair_begin(values), pair_end(values), std::back_inserter(pair_values));
for (auto const & pair : pair_values) {
std::cout << "{" << pair.first << "," << pair.second << "} ";
}
std::cout << std::endl;
}

how to display common character if the two letters is equal in vector

For example I have vector {'a','a','b','b','c'} and I want to get the most letters which is a and b but this code the output is a;
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int getMostFrequentElement(std::vector<char> &arr)
{
if (arr.empty())
return -1;
std::sort(arr.begin(), arr.end());
auto last_int = arr.front();
auto most_freq_int = arr.front();
int max_freq = 0, current_freq = 0;
for (const auto &i : arr) {
if (i == last_int)
++current_freq;
else {
if (current_freq > max_freq) {
max_freq = current_freq;
most_freq_int = last_int;
}
last_int = i;
current_freq = 1;
}
}
if (current_freq > max_freq) {
max_freq = current_freq;
most_freq_int = last_int;
}
return most_freq_int;
}
int main(){
std::vector<char> arr = {'a','a','b','b','c'};
char ret = getMostFrequentElement(arr);
std::cout << "Most frequent element = " << ret;
}
May I know why my output becomes a instead a and b?
input vector arr{'a','a','b','b','c'}
expected output is a and b
but my output is a
Your function returns only the first most frequent character as an integer in a sorted vector.
For starters the implementation of the function is not good. The function shall not sort the passed by reference vector. It is the owner of the vector decides whether to sort the vector before calling the function. The function shall not modify the passed to it vector.
If you want that the function would return all most frequent characters in a vector then you need to change the function essentially.
For example the function can look the following way as it is shown in the demonstrative program below.
#include <iostream>
#include <vector>
#include <map>
#include <iterator>
#include <algorithm>
std::vector<char> getMostFrequentElement( const std::vector<char> &v )
{
std::vector<char> result;
std::map<char, size_t> m;
for ( const auto &c : v ) ++m[c];
auto it = std::max_element( std::begin( m ), std::end( m ),
[]( const auto &p1, const auto &p2 )
{
return p1.second < p2.second;
} );
if ( it != std::end( m ) )
{
for ( const auto &p : m )
{
if ( p.second == it->second ) result.push_back( p.first );
}
}
return result;
}
int main()
{
std::vector<char> v = { 'a', 'a', 'b', 'b', 'c' };
auto result = getMostFrequentElement( v );
for ( const auto &c : result ) std::cout << c << ' ';
std::cout << '\n';
return 0;
}
The program output is
a b
The answer from Vlad is good and should be accepted.
I would like to show an additional, more "mordern" C++ solution.
The Function body is rather compact and consists only of 3 lines of code. It will count all occurences of char and sort it in decreasing order regarding the occurence.
So, the caller of this function can show all kind of information. In the example below, I show all topmost elements.
But all kind of other evaluations may be shown.
Please see:
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
#include <set>
#include <iterator>
#include <unordered_map>
// Writing some aliases to prevent later typing work and make the code a little bit more readable. ---------------------
using DataType = char;
using CounterType = unsigned int;
using Pair = std::pair<DataType, CounterType>;
using Counter = std::unordered_map<DataType, CounterType>;
using Data = std::vector<DataType>;
struct Comp { bool operator ()(const Pair& p1, const Pair& p2) const { return (p1.second == p2.second) ? p1.first<p2.first : p1.second>p2.second; } };
using CountedAndSorted = std::multiset<Pair, Comp>;
// ----------------------------------------------------------------------------------------------------------------------
CountedAndSorted getMostFrequentElement(Data& data) {
// Count
Counter counter{};
for (const char c : data) counter[c]++;
// Return counted and sorted result
return {counter.begin(), counter.end()};
}
// ------------------------
// Test/Driver code
int main() {
// Test Data
Data d = { 'a', 'a', 'b', 'b', 'c' };
// Calculate result
auto result = getMostFrequentElement(d);
// Show output
for (const auto& [c, count] : result) if (count == result.begin()->second) std::cout << c << ' ';
}

How to check if all the elements in a 2D vector are zero?

I found on Stack Overflow that this single statement can be used to find whether all the elements of a vector are zero, or not, but this is only for 1D vector.
bool zeros = std::all_of(v.begin(), v.end(), [](int i) { return i==0; });
How can I modify it so that it can work for a 2D vector?
Is it possible to implement it by just using a single statement?
Like this (assuming you mean a nested vector):
#include <algorithm>
#include <vector>
int main() {
std::vector<std::vector<int>> vs;
std::all_of(vs.begin(), vs.end(), [](const std::vector<int>& v) {
return std::all_of(v.begin(), v.end(), [](int x) { return x == 0; });
});
}
You could also do something like this:
bool check0(const std::vector<std::vector<int>> &vs) {
for(const auto& v : vs) {
for(auto x : v) {
if(x != 0) {
return false;
}
}
}
return true;
}
You can compare the disassembly of both versions here: https://godbolt.org/z/YzdW7x.
You can join the 2D vector into a single range, and apply all_of on that:
auto is_zero = [](int i) { return i==0; }; // some predicate
// vs is some 2D range
bool zeros = std::ranges::all_of(vs | std::views::join, is_zero);
Here's a demo.

C++ Return indexes of lowest values in array

I'm trying to return indexes of lowest values in an array, and i'm unable to find a good solution anywhere.
int indexofSmallestElement(double array[], int size)
{
int index = 0;
for(int i = 1; i < size; i++)
{
if(array[i] < array[index])
index = i;
}
return index;
}
This is the probably the simplest way of finding index of one value, but what if I have multiple lowest values in an array?
EDIT: Oh, I just realized from the comment that there is the possibility of duplicate values, so if the question is actually that, you could do this, it also returning a std::vector:
std::vector<int> indexesOfSmallestElements(double array[], int size)
{
std::vector<int> indexes = { 0 };
for (int i = 1; i < size; i++)
{
double current_smallest = array[indexes.front()];
if (array[i] < current_smallest) {
indexes.clear();
indexes.emplace_back(i);
}
else if (array[i] == current_smallest) {
indexes.emplace_back(i);
}
}
return indexes;
}
ORIGINAL:
"Lowest" is always only one, if you want "lower than a value", just return a std::vector.
std::vector<int> indexesOfSmallElements(double array[], int size, double value)
{
std::vector<int> indexes;
for (int i = 0; i < size; i++)
{
if (array[i] < value) {
indexes.emplace_back(i);
}
}
return indexes;
}
Array indices are a fairly inflexible concept, in C++ you can gain plenty of generality with iterators - there's a whole lot of C++ algorithms that take iterators directly, and essentially next to nothing in the standard library uses naked indices.
C++20 & onwards
We can create a minimums range view (lazy range combinator) that takes a range, and returns a range that only contains the minimums from the original range. The range isn't a new vector with filtered elements: it is a view onto the original range (e.g. onto the original vector of doubles).
#include <algorithm>
#include <ranges>
#include <vector>
template <typename Range>
auto minimums(Range && range) {
using namespace std::ranges;
auto first_min = min_element(range);
auto const is_min = [=](auto const &el){ return el == *first_min; };
return subrange(first_min, std::end(range)) | views::filter(is_min);
}
You definitely do not need to recover the indices of the array - iterators are a generic concept and apply quite widely. But just to show a solution equivalent to the one for C++17 & prior below, let's write some adapters that'll help with index recovery:
template <typename Range>
auto addressof(Range && range) {
using namespace std::ranges;
return views::transform(range, [](auto &el){ return &el; });
}
template <typename Range, typename It>
auto array_indices(Range && range, It && reference) {
using namespace std::ranges;
auto to_index = [ref_addr = &*reference](auto *el){ return ref_addr - el; };
return range | addressof | views::transform(to_index);
}
And now we can test it:
#include <cassert>
#include <iostream>
int main()
{
const double array[] = {8, 3, -1, -1, 9, -1, 5};
auto min_range = minimums(array);
{ // test
auto min = std::ranges::min_element(array);
// have we got the correct number of minimums?
auto min_size = std::distance(std::begin(min_range), std::end(min_range));
assert(min_size == std::count(std::begin(array), std::end(array), *min));
// are all of the minimums indeed minimums?
assert(std::ranges::all_of(min_range,
[=](auto &el){ return el == *min; }));
// are all of the minimums references to the array
assert(std::ranges::all_of(min_range,
[&](auto &el){ return &el >= std::begin(array) && &el < std::end(array); }));
}
for (auto &min : min_range)
std::cout << std::distance(std::begin(array), &min) << ' ';
std::cout << '\n';
}
Output:
2 3 5
C++17 through C++11
Thus, let's have a minimumLocations function that takes two forward iterators that define a range, and return a vector of iterators to all the minimums that were found:
#include <iterator>
#include <type_traits>
#include <vector>
template <typename I1, typename I2>
std::vector<I1> minimumLocations(I1 start, I2 end)
{
if (start == end) return {};
std::vector<I1> locations = {start};
std::decay<decltype(*start)>::type min = *start;
std::advance(start, 1);
for (; start != end; std::advance(start, 1)) {
auto const &value = *start;
if (value < min) {
// new minimum
locations.clear();
locations.push_back(start);
min = *start;
}
else if (value == min)
locations.push_back(start);
}
return locations;
}
For convenience's sake, we can also have an adapter function that takes a range instead of a pair of iterators. In C++, a "range" is anything that has a beginning and an end:
template <typename R>
auto minimumLocations(R &range) {
return minimumLocations(std::begin(range), std::end(range));
}
Both of the functions will work on any container that provides forward iterators - not only on arrays, but also vectors, lists, forward lists, etc. A specialized version could also be provided for pre-sorted containers.
And now a test and a demo:
#include <algorithm>
#include <cassert>
#include <iostream>
int main()
{
const double array[] = {8, 3, -1, -1, 9, -1, 5};
auto min_indices = minimumLocations(array);
{ // test
auto min = std::min_element(std::begin(array), std::end(array));
// have we got the correct numer of locations?
assert(min_indices.size() == std::count(std::begin(array), std::end(array), *min));
// are all of the locations indeed minimums?
assert(std::all_of(std::begin(min_indices), std::end(min_indices),
[=](auto it){ return *it == *min; }));
}
for (auto i : min_indices)
std::cout << std::distance(array, i) << ' ';
std::cout << '\n';
}
Output:
2 3 5

Check std::vector has duplicates

I want to check if a vector of integers has any duplicates or not, and have to return true if it does. So I try to do something like this:
vector<int> uGuess = {1,2,3,3,4,5}
vector<int> a = uGuess;
sort(a.begin(), a.end());
bool d = unique(a.begin(), a.end());
And this will not work since unqiue cannot be assigned as a bool value.
How should I proceed towards this?
If I were to write a for loop to perform the same action, how should I do that?
The algorithm you're looking for is std::adjacent_find.
// The container must be sorted!
const std::vector<int> sortedVector = {1,2,3,3,4,5};
const bool hasDuplicates = std::adjacent_find(sortedVector.begin(), sortedVector.end()) != sortedVector.end();
Unlike std::unique, std::adjacent_find doesn't modify the container.
As a bonus, std::adjacent_find returns an iterator to the first element in the duplicate "pair":
const auto duplicate = std::adjacent_find(sortedVector.begin(), sortedVector.end());
if (duplicate != sortedVector.end())
std::cout << "Duplicate element = " << *duplicate << "\n";
Looking at google for std::unique I found this page std::unique. I looked at what it did:
Eliminates all except the first element from every consecutive group of equivalent elements from the range [first, last)
So it looks like it does what you want - removes the duplicates.
I then looked at what it returns...
... returns a past-the-end iterator for the new logical end of the range
So the result from std::unique is a sequence which is not necessary the same as the whole vector.
If nothing was removed, the return value would be the end of the vector.
So you want:
vector<int>::iterator it = std::unique(a.begin(), a.end());
bool wasUnique = (it == a.end());
Or for C++11:
auto it = std::unique(a.begin(), a.end());
bool wasUnique = (it == a.end());
Finally for the unique function to work, the vector needs to be sorted, so the complete code would be:
sort(a.begin(), a.end());
auto it = std::unique(a.begin(), a.end());
bool wasUnique = (it == a.end());
You should using set
set<int> s(a.begin(), a.end());
return s.size() != a.size();
If someone is forced to write own algorithm:
bool hasDuplicates(const std::vector<int>& arr) {
for (std::size_t i = 0; i < arr.size(); ++i) {
for (std::size_t j = i + 1; j < arr.size(); ++j) {
if (arr[i] == arr[j])
return true;
}
}
return false;
}
But in real code you should use things that already exist, and in the standard library.
Sort the vector if it's not already sorted, and then use std::unique(), like this:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v = {3, 1, 3, 4, 5};
sort(v.begin(), v.end());
auto it = std::unique(v.begin(), v.end());
std::cout << ((it == v.end()) ? "Unique\n" : "Duplicate(s)\n");
return 0;
}
Output:
Duplicate(s)
So far all these solutions either modify the container or have O(n²) complexity. You can put a std::map to much better use:
#include <algorithm>
#include <iterator>
#include <map>
template <typename Iterator>
bool has_duplicates( Iterator first, Iterator last )
{
std::map <typename std::iterator_traits <Iterator> ::value_type, std::size_t> histogram;
while (first != last)
if (++histogram[ *first++ ] > 1)
return true;
return false;
}
#include <iostream>
#include <vector>
int main()
{
using std::begin;
using std::end;
int a[] = { 2, 3, 5, 7, 11 };
int b[] = { 2, 3, 5, 5, 7 };
std::vector <int> c( begin(a), end(a) );
std::vector <int> d( begin(b), end(b) );
std::cout << std::boolalpha;
std::cout << "a has duplicates false : " << has_duplicates( begin(a), end(a) ) << "\n";
std::cout << "b has duplicates true : " << has_duplicates( begin(b), end(b) ) << "\n";
std::cout << "c has duplicates false : " << has_duplicates( begin(c), end(c) ) << "\n";
std::cout << "d has duplicates true : " << has_duplicates( begin(d), end(d) ) << "\n";
}
If your vector is small, say < 32 objects, or if copying and sorting the objects is expensive or impossible due to lack of move or copy constructor/assignment then a straight O(n^2) compare everything against everything else algorithm is the way to go.
Here is my solution:
template <typename Iterator>
bool has_duplicates( Iterator first, Iterator end ) {
for (auto i = first; i != end; ++i) {
for (auto j = first; i != j; ++j) {
if (*i == *j) return true;
}
}
return false;
}
template <typename Container>
bool has_duplicates(const Container &v) {
for (const auto & i : v) {
for (const auto & j : v) {
if (&i == &j) break;
if (i == j) return true;
}
}
return false;
}