Reputation: 11728
For special values like NA
or NaN
, boost::unordered_map
creates a new key each time I use insert
.
// [[Rcpp::depends(BH)]]
#include <boost/unordered_map.hpp>
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
void test_unordered_map(NumericVector vec) {
boost::unordered_map<double, int> mymap;
int n = vec.size();
for (int i = 0; i < n; i++) {
mymap.insert(std::make_pair(vec[i], i));
}
boost::unordered_map<double, int>::iterator it = mymap.begin(), end = mymap.end();
while (it != end) {
Rcout << it->first << "\t";
it++;
}
Rcout << std::endl;
}
/*** R
x <- c(sample(10, 100, TRUE), rep(NA, 5), NaN) + 0
test_unordered_map(x)
*/
Result:
> x <- c(sample(10, 100, TRUE), rep(NA, 5), NaN)
> test_unordered_map(x)
nan nan nan nan nan nan 4 10 9 5 7 6 2 3 1 8
How do I create only one key for NA
and one for NaN
?
Upvotes: 2
Views: 245
Reputation: 26823
bartop's idea of using a custom comperator is good, although the particular form did not work for me. So I used Boost's documentation as starting point. Combined with suitable functions from R I get:
// [[Rcpp::depends(BH)]]
#include <boost/unordered_map.hpp>
#include <Rcpp.h>
using namespace Rcpp;
struct R_equal_to : std::binary_function<double, double, bool> {
bool operator()(double x, double y) const {
return (R_IsNA(x) && R_IsNA(y)) ||
(R_IsNaN(x) && R_IsNaN(y)) ||
(x == y);
}
};
// [[Rcpp::export]]
void test_unordered_map(NumericVector vec) {
boost::unordered_map<double, int, boost::hash<double>, R_equal_to> mymap;
int n = vec.size();
for (int i = 0; i < n; i++) {
mymap.insert(std::make_pair(vec[i], i));
}
boost::unordered_map<double, int>::iterator it = mymap.begin(), end = mymap.end();
while (it != end) {
Rcout << it->first << "\t";
it++;
}
Rcout << std::endl;
}
/*** R
x <- c(sample(10, 100, TRUE), rep(NA, 5), NaN) + 0
test_unordered_map(x)
*/
Result:
> x <- c(sample(10, 100, TRUE), rep(NA, 5), NaN) + 0
> test_unordered_map(x)
7 2 nan nan 4 6 9 5 10 8 1 3
As desired, NA
and NaN
are inserted only once. However, one cannot differentiate between them in this output, since R's NA
is just a special form of an IEEE NaN.
Upvotes: 6
Reputation: 10315
According to the IEEE standard, NaN values compared with ==
to anything yeilds always false. So, You just cannot do it this way. You can provide Your own comparator for unordered_map
using this std::isnan
function.
auto comparator = [](auto val1, auto val2) {
return std::isnan(val1) && std::isnan(val2) || val1 == val2;
}
boost::unordered_map<double, int, boost::hash<double>, decltype(comparator)> mymap(comparator);
Upvotes: 5