Comparator for std::algorithm::sort? - c++

vector< pair<size_t, tuple<double,double> >>
sort_indexes(const vector<tuple<double,double>> &v)
//takes a list and prepends the sorted inxdex
{
// Copy data
vector< pair<size_t, tuple<double,double> >> idx(v.size());
for (size_t i = 0; i != idx.size(); ++i)
{
idx[i].first=i ;
idx[i].second=v[i];
}
sort(idx.begin(), idx.end(),
[&v](size_t i1, size_t i2) {return get<0>(v[i1]) < get<0>(v[i2]);}
);
return idx;
}
The error looks like:
1>C:\Program Files (x86)\Microsoft Visual Studio
11.0\VC\include\algorithm(3781): error C2664: 'bool sort_indexes::::operator
()(size_t,size_t) const' : cannot convert parameter 1 from
'std::pair<_Ty1,_Ty2>' to 'size_t'
I'm confused, what is the form of the comparator? I think that it should be anything that returns a boolean? and the lambda I supplied seams to return a boolean?
When I remove the comparator the code still sorts, although this effect isn't desired as sort by the index has a predictable outcome.

You are trying to sort a vector< pair<size_t, tuple<double,double> >>, so the comparator must compare pair<size_t, tuple<double,double> >, not size_t.

simple try it in gcc-4.9, get the below information:
no known conversion for argument 1 from 'std::pair >' to 'size_t {aka long unsigned int}'
simply conclusion: your comp is not correct, you need a comparator of std::pair<size_t, std::tuple<double, double>>.

for here, sort
comp - comparison function object (i.e. an object that satisfies the requirements of Compare) which returns ​true if the first argument is less (i.e. is ordered before) the second element.
The signature of the comparison function should be equivalent to the following:
bool cmp(const Type1 &a, const Type2 &b);
The signature does not need to have const &, but the function object must not modify the objects passed to it.
The types Type1 and Type2 must be such that an object of type RandomIt can be dereferenced and then implicitly converted to both of them. ​
The type of Type1 and Type2 is pair<size_t, tuple<double,double> > in your code.

Comparator should be (if sorting by indices):
typedef pair<size_t, tuple<double,double> > param;
sort(idx.begin(), idx.end(), [&v](const param &it, const param &jt) {
return it.first < jt.first;
});
Otherwise:
typedef pair<size_t, tuple<double,double> > param;
sort(idx.begin(), idx.end(), [&v](const param &it, const param &jt) {
return std::get<0>(it.second) < std::get<0>(jt.second);
});

Related

Why C++ returns error when I use my custom constructor in priority queue?

priority_queue<pair<int, int>, vector<pair<int, int>>, comparator> pq;
static bool comparator(pair<int, int> &m, pair<int, int> &n) {
if (m.second < n.second) return true;
else return false;
}
Error:
I defined my comparator inside a class, and try to declare the priority queue inside another function in the same class, and the error happens.
The third template parameter to std::priority_queue is a type.
comparator is not a type. It is a function.
But before you can fix this, there are two more problems to fix:
types and object must be declared before they are used, and the shown code does not declare comparator before using it.
comparators must taken their parameters as const references, they are not allowed to modify them.
Therefore, your comparator should be:
static bool comparator(const pair<int, int> &m, const pair<int, int> &n)
Its type is: bool (*)(const pair<int, int> &, const pair<int, int> &)
That's what the third parameter to std::priority_queue template should be, and then the actual comparator must be passed to the object's constructor, std::priority_queue has an overloaded constructor that takes an instance of the comparator as a parameter:
static bool comparator(const pair<int, int> &m, const pair<int, int> &n) {
if (m.second < n.second) return true;
else return false;
}
priority_queue<pair<int, int>, vector<pair<int, int>>,
bool (*)(const pair<int, int> &, const pair<int, int> &)
> pq{comparator};
However, you will discover that most of this is unnecessary, and I showed it only for pedanticty's purposes. std::priority_queue's default comparator template parameter will work just fine, because std::pair implements operator<:
priority_queue<pair<int, int>, vector<pair<int, int>>> pq{comparator};
The third template argument for template type parameter must be a type, whereas comparator is a function. You may get the type of the function with decltype(&comparator).
std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, decltype(&comparator)> pq(comparator);
The last cppreference example with lambda is very similar to your code https://coliru.stacked-crooked.com/view?id=86f63b09847ba22e.

Difficulties with std::greater<int>() comparator with partial_copy_sort, "no matching function call.." on Mac OSX

Currently working with some ol' C++, but am having a touch of trouble with using the greater<int>() comparator for finding the top k keys with the max value in a map.
When compiling receiving the error:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:5138:17: error: no matching function for call to object of type 'std::__1::greater<int>'
if (__comp(*__first, *__result_first))
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/algorithm:5160:12: note: in instantiation of function template specialization 'std::__1::__partial_sort_copy<std::__1::greater<int> &, std::__1::__hash_map_iterator<std::__1::__hash_iterator<std::__1::__hash_node<std::__1::__hash_value_type<std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, int>, void *> *> >, std::__1::__wrap_iter<std::__1::pair<std::__1::vector<std::__1::basic_string<char>, std::__1::allocator<std::__1::basic_string<char> > >, int> *> >' requested here
return __partial_sort_copy<_Comp_ref>(__first, __last, __result_first, __result_last, __comp);
^
Yikes that's ugly... Here's some context:
Context
I have an unordered_map<vector<string>,int>> construct which I am attempting to find the top k strings in my map which have the max int value.
#include <string>
#include <unordered_map>
#include <algorithm>
#include <functional>
#include <vector>
//...
unordered_map<vector<string>, int> database;
vector<pair <vector<string>, int> > top_k(3);
partial_sort_copy(my_map.begin(),
my_map.end(),
top_k.begin(),
top_k.end(),
greater<int>());
Not the best cpp programmer, would love to hear some suggestions you had to remedy this situation?
According to the documentation on cppreference, the comparator function requires a type signature like so:
bool cmp(const Type1 &a, const Type2 &b);
The types Type1 and Type2 must be such that an object of type RandomIt can be dereferenced and then implicitly converted to both of them. ​
The RandomIt iterators correspond to the top_k structure which when dereferenced has type pair <vector<string>, int>, while std::greater<int> has comparison function of bool operator()( const int& lhs, const int& rhs ). In other words, this does not work because pair <vector<string>, int> does not convert to int.
One solution is to provide your own comparator:
std::partial_sort_copy(my_map.begin(), my_map.end(), top_k.begin(), top_k.end(),
[](const pair<vector<string>, int>& lhs, const pair<vector<string>, int>& rhs) {
return lhs.second > rhs.second;
});

C++ bool std::operator < error with map with key std::unordered_set<int,std::hash<int>>

when I try to insert in this map:
std::map<std::unordered_set<int >, std::pair<float, std::pair<float, float >> >
I got this error
error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const
std::_Tree<_Traits> &)' : could not deduce template argument for
'const std::_Tree<_Traits> &' from 'const
std::unordered_set,std::equal_to<_Kty>,std::allocator<_Kty>>'
My data is defined as follows:
struct Trans {
int Item;
float Prob;
float W;
};
bool operator<(const Trans &a, const Trans &b)
{
return a.Item < b.Item;
}
bool operator==( Trans c, Trans d) { return c.Item == d.Item; }
struct MyHash {
size_t operator()(const Trans& x) const { return std::hash<int>()(x.Item); }
};
std::vector<std::vector<Trans>> data;
std::map<std::unordered_set<int>, float> S1;
std::map<std::unordered_set<int >, std::pair<float, std::pair<float, float >> > S2;
std::map<std::unordered_set<int >, std::pair<float, std::pair<float, float >> > S3;
The part that has the problem:
do
{
std::unordered_set<Trans, MyHash> KS(data[i].begin(), data[i].begin() + k);
std::unordered_set<int > elem;
float esupp = 1;
float Weight = 0;
float Wesupp = 1;
for (auto const &iter : KS)
{
elem.insert(iter.Item);
esupp *= iter.Prob;
Weight += iter.W;
}
Weight = Weight / k;
/*
some code, and until here I didn't get any problem
*/
**// This the area that has the problem**
S1[elem] = std::move(S1[elem] + esupp);
Wesupp = Weight * S1[elem];
S2[elem].first = std::move(S2[elem].first + esupp);
S2[elem].second = std::make_pair(elem, Wesupp);
} while (next_combination(data[i].begin(), data[i].begin() + k, data[i].end()));
A std::map expects its key to implement the operator <, unless a comparator is supplied.
Your key type, std::unordered_set doesn't implement "less than".
As #T.C. mentions, you could use std::set instead of std::unordered_set.
Your current error, as Drew Dormann pointed out, is caused by std::unordered_set's lack of an operator <.
std::set, however, does have an overloaded operator <, so you can use that.
The problem with your code runs deeper than that, though. For instance:
S1[elem] = std::move(S1[elem] + esupp);
You are assigning a float. There's absolutely no point in using std::move, especially as S1[elem] + esupp is already an rvalue. The usual way of writing this line would be S1[elem] += esupp;
S2[elem].first = std::move(S2[elem].first + esupp);
Same problem.
S2[elem].second = std::make_pair(elem, Wesupp);
The LHS of the assignment is a std::pair<float, float>; the RHS creates a std::pair<std::unordered_set<int>, float>.
And as I mentioned in the comments, std::pair<float, std::pair<float, float>> is just bad design. It should be at least std::tuple or even better a std::array<float, 3> or even better a simple struct that makes clear what each of the three floats actually mean.
Further, using a set<int> (unordered or not) as a key in a map is a fairly weird design. Do you want to just maintain a list of set<int>-3xfloat pairings that you can iterate through, or do you actually want to be able to efficiently index with a set<int>? If you don't need the efficient indexing, just use a vector of pairs rather than a map.

error in type conversion in operator overloading

I have a template class and I need to overload operator ==. I do this in the following way
template <typename T>
class Polynomial {
vector<T> coefficients;
public:
Polynomial(vector<T> c);
bool operator ==(const Polynomial& second) const {
const typename vector<T>::iterator thisBegin = this->coefficients.begin();
const typename vector<T>::iterator secondBegin = second.coefficients.begin();
for ( ; ((thisBegin != this->coefficients.end()) &&
(secondBegin != second.coefficients.end()));
++thisBegin, ++secondBegin) {
if (*thisBegin != *secondBegin)
return false;
}
while (thisBegin != this->coefficients.end()) {
if (*thisBegin != 0)
return false;
++thisBegin;
}
while (secondBegin != second.coefficients.end()) {
if (*secondBegin != 0)
return false;
++secondBegin;
}
return true;
}
};
However, when I create two objects of this class with T=int and try to apply this operator
Polynomial<int> first(firstVector);
Polynomial<int> second(secondVector);
std::cout << (first == second) << std::endl;
I got the error
problem2.cpp: In instantiation of ‘bool Polynomial<T>::operator==(const Polynomial<T>&) const [with T = int; Polynomial<T> = Polynomial<int>]’:
problem2.cpp:63:32: required from here
problem2.cpp:23:83: error: conversion from ‘std::vector<int, std::allocator<int> >::const_iterator {aka __gnu_cxx::__normal_iterator<const int*, std::vector<int, std::allocator<int> > >}’ to non-scalar type ‘std::vector<int, std::allocator<int> >::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >}’ requested
Can someone point out what's wrong with this conversion? Thanks!
You are trying to convert a const_iterator to an iterator:
const typename vector<T>::iterator thisBegin = this->coefficients.begin();
this is const in this context, so this->coefficients.begin(); returns a const_iterator. Try this:
typename vector<T>::const_iterator thisBegin = this->coefficients.begin();
Note also that thisBegin is not const, as in your example. This is because you then do this kind of thing:
++secondBegin;
which requires the const_iterator to be non-const (meaning you can modify the iterator, but not the thing it points to).
your method is const that mean that you can only call const functions on this and
you passing const reference to method, so you can only call const functions on it
So, both
this->coefficients.begin();
second.coefficients.begin()
returns const iterators.
You cannot assign them to non-const ones.
There is a solution:
vector<T>::const_iterator& thisBegin = this->coefficients.begin();
vector<T>::const_iterator& secondBegin = second.coefficients.begin();
(use references to const_iterator)
Even better:
auto& thisBegin = this->coefficients.begin();
auto& secondBegin = second.coefficients.begin();
(use references to auto, C++11 feature)
BTW, you can simply compare two vectors using std::mismatch

find() problems

I've got an error while using find() function. Here is the code:
#include <iostream>
#include <map>
#define N 100000
using namespace std;
int main (int argc, char * const argv[]) {
map<int,int> m;
for (int i=0; i<N; i++) m[i]=i;
find(m.begin(), m.end(), 5);
return 0;
}
I'm getting an compiller error:
error: no match for 'operator==' in '__first. __gnu_debug::_Safe_iterator<_Iterator, _Sequence>::operator* [with _Iterator = std::_Rb_tree_iterator<std::pair<const int, int> >, _Sequence = __gnu_debug_def::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >]() == __val'
Including 'algorithm' nothing changes. Compiling in VS2008 shows similar error.
I know about m.find(), but I realy need to use find() too.
Thanks a lot for your assistance!
P.S. Actualy, the task is to compare speed of m.find(5) and find(m.begin(), m.end(), 5), so I need to make both of them work properly.
begin() and end() on all STL containers provide access to elements of those collections. Type of those elements is known as value_type of the container. For std::map<Key, Value>, its value_type is std::pair<Key, Value>. Therefore, your find function is trying to find a pair<int, int> which is equal to 5. Since there's no operator== defined to compare pair<int, int> and int, you get the error.
The correct way to do this (so long as you want to avoid member find()) is to use std::find_if:
template <class First>
struct first_equal
{
const First value;
first_equal(const First& value)
: value(value)
{
}
template <class Second>
bool operator() (const std::pair<First, Second>& pair) const
{
return pair.first == value;
}
};
...
find_if(m.begin(), m.end(), first_equal<int>(5));
You could also overload operator== for pair and int to do what you want, but it's a very hackish way (because it will affect all your code, and because such a comparison has no meaning in general).
find() requires a parameter that can be compared to *iterator. For your map, this will be pair<int,int>. You'll need to create a dummy pair, plus a comparison functor to compare the pairs.
Just use m.find(5)