Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

subset a vector and sort it

Tags:

c++

r

rcpp

I'm looking into using some C++ for simple parts of my R package using the Rcpp package. I'm a C++ novice (but keen to learn!). I've implemented a few simple cpp programs using the excellent Rcpp - in fact that package has motivated me to learn C++...

Anyway, I've got stuck with a simple problem, which if I can fix would help lots. I have a NumericVector I want to subset and then sort. The code below sorts the whole vector (and would also deal with NAs, which is what I need).

My question is, say I want to extract a part of this vector, sort and have it available for other processing - how can I do that? For example, for a vector of length 10, how do I extract and sort the elements 5:10?

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
RcppExport SEXP rollP(SEXP x) {
  NumericVector A(x); // the data  
  A = sort_unique(A);  
  return A;
}

which I call from R:

sourceCpp( "rollP.cpp")
rollP(10:1)
# [1]  1  2  3  4  5  6  7  8  9 10
like image 485
DavidC Avatar asked Nov 22 '12 20:11

DavidC


People also ask

How can I sort a vector?

Sorting a vector in C++ can be done by using std::sort(). It is defined in<algorithm> header. To get a stable sort std::stable_sort is used. It is exactly like sort() but maintains the relative order of equal elements.

Can we sort vector of vector?

A vector in C++ can be easily sorted in ascending order using the sort() function defined in the algorithm header file. The sort() function sorts a given data structure and does not return anything. The sorting takes place between the two passed iterators or positions.

What happens when we sort vector of vectors?

In this type of sorting 2D vector is entirely sorted on basis of a chosen column. For example, if the chosen column is second, the row with the smallest value in the second column becomes the first row, the second smallest value in the second column becomes the second row, and so on.


4 Answers

Here are 3 variants:

include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector rollP(NumericVector A, int start, int end) {
  NumericVector B(end-start+1) ;
  std::copy( A.begin() + start-1, A.begin() + end, B.begin() ) ;
  return B.sort() ;
}

// [[Rcpp::export]]
NumericVector rollP2(NumericVector A, int start, int end) {
  NumericVector B( A.begin() + start-1, A.begin() + end ) ;
  return B.sort() ;
}

// [[Rcpp::export]]
NumericVector rollP3(NumericVector A, int start, int end) {
  NumericVector B = A[seq(start-1, end-1)] ;
  return B.sort() ;
}

start and end are meant as 1-based indices, as if you were passing A[start:end] from R.

like image 144
Romain Francois Avatar answered Oct 08 '22 19:10

Romain Francois


You need to look into C++ indexing, iterators and the whole bit. At a minimum, you need to change your interface (vector, fromInd, toInd) and figure out what you want to return.

One interpretation of your question would be to copy the subset from [fromInd, toInd) into a new vector, sort it and return it. All that is standard C++ fare, and a good text like the excellent (and free!!) C++ Annotations will be of help. It has a pretty strong STL section too.

like image 30
Dirk Eddelbuettel Avatar answered Oct 08 '22 18:10

Dirk Eddelbuettel


You can use std::slice on a std::valarray. But if you want to use std::vector specifically then you can use std::copy to extract a portion of the vector and then use std::sort to sort the extracted slice of the vector.

like image 35
yasouser Avatar answered Oct 08 '22 19:10

yasouser


You can do this quite easily by using the std::sort implementation that receives two iterators:

#include <vector>
#include <cinttypes>
#include <algorithm>

template <typename SeqContainer>
SeqContainer slicesort(SeqContainer const& sq, size_t begin, size_t end) {
  auto const b = std::begin(sq)+begin;
  auto const e = std::begin(sq)+end;
  if (b <= std::end(sq) && e <= std::end(sq)) {
    SeqContainer copy(b,e);
    std::sort(copy.begin(),copy.end());
    return copy;
  }
  return SeqContainer();
}

Which can be invoked like

  std::vector<int> v = {3,1,7,3,6,-2,-8,-7,-1,-4,2,3,9};
  std::vector<int> v2 = slicesort(v,5,10);
like image 31
bitmask Avatar answered Oct 08 '22 17:10

bitmask