Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I reverse numbers in a vector ONLY if they are sequential?

So, if the input is a vector such as

v <- (1, 2, 3, 7, 2, 8, 9) 

The output would be

(3, 2, 1, 7, 2, 9, 8)

I have tried using nested for and if loops with the condition as an is.sorted function, but have not had any success.

like image 445
tdm Avatar asked Mar 27 '17 20:03

tdm


People also ask

How do you reverse a vector order?

R – Reverse a Vector To reverse a vector in R programming, call rev() function and pass given vector as argument to it. rev() function returns returns a new vector with the contents of given vector in reversed order. The rev() function returns a vector.

How do you reverse a list without using reverse function?

In order to reverse a list without using the built-in reverse() function, we use the Slicing Operator. The slicing operator is another method used for reversing the data elements.

How do you reverse a number sequence in C++?

Convert the given number (say n) to a string (say str) using the to_string(n) function. Then reversing str using the inbuilt reverse function. Printing str, which now holds n in reversed form.


2 Answers

With the sample data

x <- c(1, 2, 3, 7, 2, 8, 9)

You can partition into "sequential groups" with

grp <- cumsum(!c(TRUE, diff(x)==1))
grp
# [1] 0 0 0 1 2 3 3

Basically we look at the diff from the previous element and track changes anytime that value isn't equal to 1.

You can use this group information to re-order those values with ave (this does a within-group transformation).

revsort<-function(...) sort(...,decreasing=TRUE)
ave(x, grp, FUN=revsort)
# [1] 3 2 1 7 2 9 8
like image 159
MrFlick Avatar answered Oct 21 '22 00:10

MrFlick


We could also do:

x <- c(0, which(diff(vec) != 1), length(vec))
unlist(sapply(seq(length(x) - 1),  function(i) rev(vec[(x[i]+1):x[i+1]])))

#[1] 3 2 1 7 2 9 8

The idea is to first cut the vector based on the positions of consecutive numbers. We then traverse these cuts and apply rev.


Data

vec <- c(1, 2, 3, 7, 2, 8, 9)

Benchmarking

library(microbenchmark)
vec1 <- c(1, 2, 3, 7, 2, 8, 9)
vec2 <- c(1:1000, sample.int(100, 10), 5:500, sample.int(100, 10), 100:125)

f_MrFlick <- function(x){
    revsort<-function(...) sort(...,decreasing=TRUE)
    grp <- cumsum(!c(TRUE, diff(x)==1))
    ave(x, grp, FUN=revsort)
}

f_989 <- function(vec){
    x <- c(0, which(diff(vec) != 1), length(vec))
    unlist(sapply(seq(length(x) - 1),  function(i) rev(vec[(x[i]+1):x[i+1]])))
}

all(f_MrFlick(vec1)==f_989(vec1))
# [1] TRUE
all(f_MrFlick(vec2)==f_989(vec2))
# [1] TRUE

length(vec1)
# [1] 7
microbenchmark(f_MrFlick(vec1), f_989(vec1))
# Unit: microseconds
            # expr     min       lq     mean  median       uq     max neval
 # f_MrFlick(vec1) 287.006 297.0585 305.6340 302.833 312.6695 479.912   100
     # f_989(vec1) 113.348 119.7645 124.7901 121.903 127.0360 268.186   100
# --------------------------------------------------------------------------
length(vec2)
# [1] 1542 
microbenchmark(f_MrFlick(vec2), f_989(vec2))
# Unit: microseconds
            # expr      min        lq      mean   median       uq      max neval
 # f_MrFlick(vec2) 1532.553 1565.2745 1725.7540 1627.937 1698.084 3914.149   100
     # f_989(vec2)  426.874  454.6765  546.9115  466.439  489.322 2634.383   100
like image 42
989 Avatar answered Oct 21 '22 00:10

989