1

Below I have a code snippet that encapsulates an issue I am having.

What I am trying to do would be trivial in R, but is much more difficult in Rcpp. I am just trying aggregate values according to their respective keys. In this example, I am just trying to get the sum of the values that correspond with the first key. I have done something very similar in C++, but for some reason, the Rcpp port is giving me issues.

Also, note that the code provided is only meant to represent an issue I am having with something much larger. So I understand that attempting to implement this in Rcpp alone is not a good use of time.

#include <Rcpp.h>
using namespace Rcpp;
using namespace std;
// [[Rcpp::export]]

int mmap(List x) {

std::multimap<int, int> out;

  for(int i = 0; i < x.size(); ++i) {
    int key_temp = as<List>(as<List>(x[i]))[0];
    int value_temp = as<List>(as<List>(x[i]))[1];
    out.insert(make_pair(key_temp, value_temp));  
  }

 pair<multimap<int, int>::iterator, multimap<int, int>::iterator> range = out.equal_range(1);
 int total = accumulate(range.first, range.second,  0);

  return total;
}

/*
xList <- list()
xList[[1]] <- list()
xList[[1]][1] <- 1
xList[[1]][2] <- 1
xList[[2]] <- list()
xList[[2]][1] <- 1
xList[[2]][2] <- 2
xList[[3]] <- list()
xList[[3]][1] <- 2
xList[[3]][2] <- 2
xList[[4]] <- list()
xList[[4]][1] <- 1
xList[[4]][2] <- 2

mmap(xList)
 */
R_user1233
  • 450
  • 1
  • 4
  • 9
  • A few things seem odd: your `out` is a `multimap` yet later you use iterators of a `multimap` of `vector` rather than `int`. On purpose? – Dirk Eddelbuettel Jun 24 '18 at 03:19
  • No not on purpose thank you for the catch. If this is not the correct usage of equal_range, what would you say I do? I am sure I could write a loop, I just thought there would be a simpler solution. Though I am the farthest thing from a C++ expert, so I could be wrong. – R_user1233 Jun 24 '18 at 03:42
  • I mucked with it for a moment or two, and I got most things fixed but I do not know if the `accumulate()` can work over the `pair` of iterators. Pages of compiles issues. – Dirk Eddelbuettel Jun 24 '18 at 03:45
  • 2
    It's a bad idea to have `using namespace std` especially when you already have `using namespace Rcpp`. – Joseph Wood Jun 24 '18 at 11:44

1 Answers1

4

One of the first error messages you get is instructive:

/usr/include/c++/7/bits/stl_numeric.h:127:18: error: no match for ‘operator+’ (operand types are ‘int’ and ‘std::pair’)

The compiler does not know how to add your starting value (an int) with the new value from the iterator (a pair representing the key-value-pair). Fortunately std::accumulate takes an optional argument with a function that is to be applied. Using C++11 we can use a simple lambda function:

#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::export]]
int mmap(List x) {

  std::multimap<int, int> out;

  for(int i = 0; i < x.size(); ++i) {
    int key_temp = as<List>(as<List>(x[i]))[0];
    int value_temp = as<List>(as<List>(x[i]))[1];
    out.insert(std::make_pair(key_temp, value_temp));  
  }

  auto range = out.equal_range(1);
  int total = std::accumulate(range.first, range.second,  0,
                         [](int a, std::pair<const int, int> b) { return a + b.second; });

  return total;
}

/*** R
 xList <- list()
 xList[[1]] <- list()
 xList[[1]][1] <- 1
 xList[[1]][2] <- 1
 xList[[2]] <- list()
 xList[[2]][1] <- 1
 xList[[2]][2] <- 2
 xList[[3]] <- list()
 xList[[3]][1] <- 2
 xList[[3]][2] <- 2
 xList[[4]] <- list()
 xList[[4]][1] <- 1
 xList[[4]][2] <- 2

 mmap(xList)
 */

Result:

> mmap(xList)
[1] 5
Ralf Stubner
  • 26,263
  • 3
  • 40
  • 75