5

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

Cypress
  • 337
  • 2
  • 9
  • Could you consider posting sample input and the desired output? Isn't reversing simply concerned with changing the order? – Konrad Mar 06 '16 at 09:48
  • 1
    Although it's probably not the best way, I'd guess you are trying to do `paste(rev(strsplit(as.character(n),"")[[1]]), collapse = "")`. Though as mentioned, it's better to provide a reproducible example and desired output. – David Arenburg Mar 06 '16 at 09:51
  • Thank you guys. I have just updated my question wit input and desired output. – Cypress Mar 06 '16 at 10:30
  • For questions like these, I guess the first place to look is the ["mathematics"](http://math.stackexchange.com/questions/480068/how-to-reverse-digits-of-an-integer-mathematically) community - so, you could use `ff = function(x) x * 10^floor(log10(x)) - 99 * sum(floor(x * 10^(-seq_len(floor(log10(x))))) * 10^(floor(log10(x)) - seq_len(floor(log10(x))))) `; `ff(4568742)`. You could store some computations to avoid repeting them. – alexis_laz Mar 06 '16 at 11:25

3 Answers3

10

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  
David Arenburg
  • 89,637
  • 17
  • 130
  • 188
  • Just a note in the second function - if input 'x' is indeed "integer" (I assume a "double" will be automatically coerced before passed to the function) then the original 'x' will be modified. – alexis_laz Mar 06 '16 at 12:26
  • @alexis_laz I'm not sure what you mean. How can you reverse `12.3`? Or in which case your `ff` work and this won't? Also `Reverse_CPP2(as.double(c(12, 24)))` will work fine. While `Reverse_CPP2(as.double(12.3))` indeed will convert to an integer while `ff(12.3)` will return some other result. Either way, I didn't understand your comment. – David Arenburg Mar 06 '16 at 12:30
  • I was refering to the 'typeof's; see -for example- `x1 = 12; Reverse_CPP2(x1); x1; x2 = 12L; Reverse_CPP2(x2); x2` – alexis_laz Mar 06 '16 at 12:34
  • @alexis_laz wow, I have no idea what happened there. Can you point out to some documentation on that matter? So basically saying the function modifies x in place? – David Arenburg Mar 06 '16 at 12:38
  • I guess "Writing R Extensions" warns about modifying input. In this case I believe, "Rcpp" automatically uses (?) sort of `coerceVector` (which returns a different object) when input's 'typeof' does not match the expected, while -when it matches- the same pointer to the R object is manipulated. (I guess in this case just saving `x[i]` to a `tmp` will fix this). – alexis_laz Mar 06 '16 at 12:45
  • @alexis_laz hmm.. So I guess I will need to add `IntegerVector xx = Rcpp::clone(x) ;` or something... – David Arenburg Mar 06 '16 at 12:48
  • No need here to duplicate at first; just save `x[i]` to a temporary "int" in each iteration and modify that. – alexis_laz Mar 06 '16 at 12:57
  • @alexis_laz I found [this](http://stackoverflow.com/questions/11300048/rcpp-pass-by-reference-vs-by-value) where Dirk addresses this issue. I will try your suggestion too, thanks. – David Arenburg Mar 06 '16 at 13:00
0

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.

Community
  • 1
  • 1
RHertel
  • 22,694
  • 5
  • 36
  • 60
0

An R function to reverse numbers based on integer division with successive powers of 10. This came up in a school project related to palindrome numbers.

Reverse_number <- function(x){ 
  n <- trunc(log10(x)) # now many powers of 10 are we dealing with 
  x.rem <- x # the remaining numbers to be reversed 
  x.out <- 0 # stores the output 
  for(i in n:0){
  x.out <- x.out + (x.rem %/% 10^i)*10^(n-i) # multiply and add 
  x.rem <- x.rem - (x.rem %/% 10^i)*10^i # multiply and subtract 
  } 
return(x.out) 
}
Tony Ladson
  • 3,229
  • 1
  • 21
  • 28