问题
How can you reverse a string of numbers in R?
for instance, I have a vector of about 1000 six digit numbers, and I would like to know if they are palindromes. I would like to create a second set which is the exact reverse, so I could do a matchup.
回答1:
It is actually the decimial representation of the number that you are testing to be a palindrome, not the number itself (255 is a palendrome in hex and binary, but not decimal).
You can do this fairly simply using pattern matching:
> tmp <- c(100001, 123321, 123456)
> grepl( '^([0-9])([0-9])([0-9])\\3\\2\\1$', tmp )
[1] TRUE TRUE FALSE
>
you could convert the numbers to character, split into individual characters (strsplit), reverse each number (sapply and rev), then paste the values back together (paste) and covert back to numbers (as.numeric). But I think the above is better if you are just interested in 6 digit palendromes.
回答2:
I don't think rev
quite does it. It reverses the elements of the vector, while the question is how to reverse the elements in the vector.
> nums <- sapply(1:10,function(i)as.numeric(paste(sample(1:9,6,TRUE),collapse="")))
> nums
[1] 912516 568934 693275 835117 155656 378192 343266 685182 298574 666354
> sapply(strsplit(as.character(nums),""), function(i) paste(rev(i),collapse=""))
[1] "615219" "439865" "572396" "711538" "656551" "291873" "662343" "281586" "475892" "453666"
回答3:
Edit: I misread the question. Here's my answer for posterity.
You can use the rev
function:
> 1:10
[1] 1 2 3 4 5 6 7 8 9 10
> rev(1:10)
[1] 10 9 8 7 6 5 4 3 2 1
回答4:
This should work in the general case, with any choice of base:
is.palindromic <- function(x, base=10)
{
p <- 0
m <- floor(log(x,base))
sig <- -1
for (i in m:0)
{
tp <- floor(x/base^i)
a <- i+1
b <- m+1-i
if(a==b){c<-0}else{c<-a*b;sig<-sig*-1}
p <- p + tp*c*sig
x <- x - tp*base^i
}
return(!as.logical(p))
}
回答5:
There is function in stringi
package for that - stri_reverse
require(stringi)
stri_reverse("123456")
## [1] "654321"
Now palindrome function might as simple as that:
palindrome <- function(x) stri_reverse(x)==x
palindrome(c("651156","1234321"))
## [1] TRUE TRUE
回答6:
If you are interested in the reversals for their own sake, you can use sub with a longer version of Greg's regexp:
> x
[1] 123321 343324 563660
> sub( '^([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])','\\6\\5\\4\\3\\2\\1', x)
[1] "123321" "423343" "066365"
Although is this quicker than split/rev/paste?
回答7:
Using intToUtf8 to split, then reverse:
tmp <- c(100001, 123321, 123456)
res <- sapply(tmp, function(i) intToUtf8(rev(utf8ToInt(as.character(i)))))
res
# [1] "100001" "123321" "654321"
To check if it is a palindrome:
tmp == res
# [1] TRUE TRUE FALSE
Benchmark
# bigger vector
tmpBIG <- rep(c(100001, 123321, 123456), 4000)
bench::mark(
GregSnow = { grepl( '^([0-9])([0-9])([0-9])\\3\\2\\1$', tmpBIG) },
bartektartanus = { tmpBIG == stringi::stri_reverse(tmpBIG) },
Spacedman = { tmpBIG == sub( '^([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])','\\6\\5\\4\\3\\2\\1', tmpBIG) },
Joshua = { tmpBIG == sapply(strsplit(as.character(tmpBIG),""), function(i) paste(rev(i),collapse="")) },
zx8754 = { tmpBIG == sapply(tmpBIG, function(i) intToUtf8(rev(utf8ToInt(as.character(i))))) },
relative = TRUE)[, 1:9]
# expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time
# <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl> <int> <dbl> <bch:tm>
# 1 GregSnow 1 1 6.82 1 NaN 23 0 517ms
# 2 bartektartanus 1.38 1.34 5.02 2.33 NaN 17 0 520ms
# 3 Spacedman 1.58 1.55 4.52 2.33 NaN 15 0 509ms
# 4 Joshua 5.82 5.56 1.24 5.29 Inf 5 6 617ms
# 5 zx8754 6.06 6.17 1 3.98 Inf 4 4 614ms
来源:https://stackoverflow.com/questions/3763518/reverse-digits-in-r