特殊值不能用作unordered_map中的键

时间:2018-08-23 12:42:33

标签: c++ r boost rcpp

对于NANaN之类的特殊值,每次使用boost::unordered_mapinsert都会创建一个新密钥。

// [[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)
*/

结果:

> 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   

如何仅为NA创建一个密钥,为NaN创建一个密钥?

2 个答案:

答案 0 :(得分:6)

使用自定义编译器的

bartop's idea很好,尽管特定的格式对我不起作用。因此,我以Boost's documentation为起点。结合合适的functions from R,我得到:

// [[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)
*/

结果:

> 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   

根据需要,NANaN仅插入一次。但是,由于R的NA只是special form of an IEEE NaN,因此无法在此输出中区分它们。

答案 1 :(得分:5)

根据IEEE标准,与==相比,NaN值始终等于false。因此,您就是不能这样做。您可以使用此std::isnan函数为unordered_map提供自己的比较器。

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);