Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reverse a number in R

Tags:

r

I want to write a function to reverse the order of any numbers. Here is what I have but it doesn't work. Please help me!

n=123
rev_number=function(n){
 m=strsplit(as.character(n),"")
 if (m==rev(m)) print("reversed number")
}

The desired output is n=321

like image 270
Cypress Avatar asked Mar 06 '16 09:03

Cypress


2 Answers

I feel like reverse an integer should stay in the integer world instead of getting into the string manipulation world. It seems there isn't a built in function for such task in R, so we can create one, using the Rcpp package for instance. Here's an example

library(Rcpp)
cppFunction('int Reverse_CPP(int x) {
  int reverse = 0;
  while(x != 0) {
        int remainder = x%10;
        reverse = reverse*10 + remainder;
        x/= 10;
    }
  return reverse ; 
}')

Reverse_CPP(1234)
# [1] 4321

And here's a vectorized version

cppFunction('IntegerVector Reverse_CPP2(IntegerVector x) {
  int n = x.size();
  IntegerVector out(n);
  IntegerVector xx = clone(x); // Will need this if you don"t want to modify x in place

  for (int i = 0; i < n; ++i){
    int reverse = 0;
    while(xx[i] != 0) {
       int remainder = xx[i]%10;
       reverse = reverse*10 + remainder;
       xx[i]/= 10;
    }
    out[i] = reverse;
   }

   return out;

}')

Reverse_CPP2(c(12345, 21331, 4324234, 4243))
# [1]   54321   13312 4324234    3424

Note that I had to add IntegerVector xx = clone(x); and hence slow the function drastically (see @alexis_laz comment) as Rcpp will modify the original x by reference otherwise. You don't need that if you are passing a bare vector or if you don't care if the original vector is being modifyied


Some benchmarks against other vectorized string manipulation functions

Stringi <- function(x) as.integer(stringi::stri_reverse(x))

Base <- function(x) {
  as.integer(vapply(lapply(strsplit(as.character(x), "", fixed = TRUE), rev),
                    paste, collapse = "", FUN.VALUE = character(1L)))
}


library(microbenchmark)
set.seed(123)
x <- sample(1e3L:1e7L, 1e5, replace = TRUE)

microbenchmark(
               Base(x),
               Stringi(x),
               Reverse_CPP2(x)
)

# Unit: milliseconds
#            expr        min         lq      mean     median          uq         max neval cld
#         Base(x) 855.985729 913.602215 994.60640 976.836206 1025.482170 1867.448511   100   c
#      Stringi(x)  86.244426  94.882566 105.58049 102.962924  110.334702  179.918461   100  b 
# Reverse_CPP2(x)   1.842699   1.865594   2.06674   1.947703    2.076983    6.546552   100 a  
like image 86
David Arenburg Avatar answered Sep 30 '22 14:09

David Arenburg


For integers n > 9 this function can be used:

reverse_int <- function(n) {
  t1 <- floor(log10(n))
  t2 <- 0
  for (i in t1:1) t2 <- t2 + floor(n/10^i) * 10^(t1-i)
  return(n*10^t1 - 99*t2)
}
reverse_int(678754)
#[1] 457876

Note that the function is not vectorized; it only takes one parameter n as input.

like image 32
RHertel Avatar answered Sep 30 '22 16:09

RHertel