Reputation: 2225
I have a std::vector with the element as pair and need to find all the elements with the first component within some ranges, for example, to find all elements such that abs(value of first component - reference)<0.01, I got the code from other post that
bool comp(pair<double, double> v1, pair<double, double> v2)
{
return (abs(v1.first-v2.first)<0.001);
}
vector< pair<double, double> data;
for (int i=0; i<10; i++)
{
double a, b;
// a & b are initialized randomly (the code was not shown here)
data.push_back(make_pair(a, b));
}
// we sort the vector here based on the pair.first (code not shown)
// compval is used as reference value, i.e. we are going to find all elements with abs(pair.first-ref.first)<0.01
pair<double, double> ref
ref.first = 0.5;
ref.second = 0.5;
std::pair< vector< pair<double, double>::iterator, vector< pair<double, double>::iterator> const range = std::equal_range(data.begin(), data.end(), ref, comp);
but if you look at all elements given by the resulting ranges, you will see that all elements of the data instead of the one satisfying abs(pair.first-ref.first)<0.01 will be returned. Is that anything I miss in the code? Thanks.
Upvotes: 0
Views: 3768
Reputation: 78330
Your comparison function does not satisfy the requirements of strict weak ordering, i.e. for two elements say a and b, if comp(a, b) == true
then comp(b, a)
should be false
.
You maybe want something more like this:
struct Comp {
double target;
bool operator()(const pair<double, double>& lhs,
const pair<double, double>& rhs) const {
return abs(lhs.first - target) < abs(rhs.first - target);
}
};
vector< pair<double, double> > data;
data.push_back(make_pair(0.1, 1.0));
data.push_back(make_pair(0.15, 1.2));
data.push_back(make_pair(0.189, 2.1));
data.push_back(make_pair(0.19, -2.1));
data.push_back(make_pair(0.192, 3.1));
data.push_back(make_pair(0.2, 0.1));
data.push_back(make_pair(0.205, 0.1));
data.push_back(make_pair(0.205, 0.0));
data.push_back(make_pair(0.206, 12.1));
data.push_back(make_pair(0.21, -12.9));
data.push_back(make_pair(0.3, 3.4));
data.push_back(make_pair(0.5, 7.5));
// We *must* sort the vector using the same comparison function that we're
// about to use to get the lower and upper bounds
Comp comp;
comp.target = 0.2;
sort(data.begin(), data.end(), comp);
// Get the lower bound
pair<double, double> low(make_pair(comp.target, 0.0));
vector< pair<double, double> >::iterator lower =
lower_bound(data.begin(), data.end(), low, comp);
// Get the upper bound
pair<double, double> up(make_pair(comp.target + 0.01, 0.0));
// N.B. use "lower_bound" here to get upper bound of target + 0.01 exclusive.
// If we want to include target + 0.01, use "upper_bound"
vector< pair<double, double> >::iterator upper =
lower_bound(data.begin(), data.end(), up, comp);
for_each(lower, upper, [](const pair<double, double> &data_point) {
cout << data_point.first << "\t" << data_point.second << "\n";
});
which outputs:
0.2 0.1
0.205 0.1
0.205 0
0.206 12.1
0.192 3.1
0.21 -12.9
Upvotes: 0
Reputation: 40613
equal_range
requires a sorted range.
The order implied by your comparison function does not match the order that you sorted the range into - and so the call to equal_range
has undefined behaviour.
For example - say your list contained {{.5, 0}, {.6, 0}}
(these are sorted), and you then applied std::bind(comp({.5,.5},_1))
to each element.
comp({.5,.5},{.5,0})
would return true.
comp({.5,.5},{.6,0})
would return false.
Your sort order is saying: ".5
is less than .6
", but at the same time your comp
function is saying ".6
is less than .5
" (because a there is a value which is less than .5
but not less than .6
). This is contradictory, and the cause of your problems.
To actually find all the elements such that std::bind(comp({.5,.5}, _1))
returns true, you could use std::copy_if(data.begin(), data.end(), some_output_iterator, std::bind(comp(ref, std::placeholders::_1)))
(although there are a variety of different ways of doing this, depending on your exact needs).
Upvotes: 2