Cypress
Cypress

Reputation: 357

How to reverse a number in 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

Upvotes: 7

Views: 12119

Answers (5)

ThomasIsCoding
ThomasIsCoding

Reputation: 102710

Here are some other base R options using utf8ToInt or substring

> n <- 123478634

> as.integer(intToUtf8(rev(utf8ToInt(as.character(n)))))
[1] 436874321

> as.integer(paste0(substring(n, nchar(n):1, nchar(n):1), collapse = ""))
[1] 436874321

Upvotes: 1

Pubudu Nawarathna
Pubudu Nawarathna

Reputation: 31

Here's my attempt by extending your code

n=-123
rev_number=function(n){
  if(n>0)
  return(as.integer(paste0(rev(unlist(strsplit(as.character(n), ""))), collapse = "")))
  else{
    return(-as.integer(paste0(rev(unlist(strsplit(as.character(abs(n)), ""))), collapse = "")))
  }
}
rev_number(n)

If else is to handle negative numbers. First it converts the integer to characters and then uses strsplit to split the number. Then unlist is used to convert the list to vector. Then we can use rev to reverse the vector and collapse the vector using paste. Finally as.integer is used to convert the string in to int.

If you do not wish to convert the number to characters, below one does not need any additional packages but only works with positive integers

reverse_number <- function(n){
rev <- 0

while (n > 0) {
  r <- n %% 10
  rev <- rev * 10 + r
  n <- n %/% 10
}

return(rev)
}
reverse_number(134576)

Upvotes: 2

Tony Ladson
Tony Ladson

Reputation: 3649

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

Upvotes: 1

David Arenburg
David Arenburg

Reputation: 92300

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  

Upvotes: 13

RHertel
RHertel

Reputation: 23818

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.

Upvotes: 1

Related Questions