3

I have a vector of values (say 1:10), and want to repeat certain values in it 2 or more times, determined by another vector (say c(3,4,6,8)). In this example, the result would be c(1,2,3,3,4,4,5,6,6,7,8,8,9,10) when repeating 2 times.

This should work for an arbitrary length range vector (like 200:600), with a second vector which is contained by the first. Is there a handy way to achieve this?

sds
  • 65
  • 1
  • 1
  • 10
  • might be better to make you example vector more random than 1:10 since you want it to work with arbitrary vectors – talat Apr 03 '17 at 14:06
  • Yes, true. The example I actually need is sorted as well, so I will add that to the question. – sds Apr 03 '17 at 14:58

4 Answers4

6

Akrun's is a more compact method, but this also will work

# get rep vector
reps <- rep(1L, 10L)
reps[c(3,4,6,8)] <- 2L

rep(1:10, reps)
 [1]  1  2  3  3  4  4  5  6  6  7  8  8  9 10

The insight here is that rep will take an integer vector in the second argument the same length as the first argument that indicates the number of repetitions for each element of the first argument.

Note that this solution relies on the assumption that c(3,4,6,8) is the index or position of the elements that are to be repeated. Under this scenario, then d-b's comment has a one-liner

rep(x, (seq_along(x) %in% c(3,4,6,8)) + 1)

If instead, c(3,4,6,8) indicates the values that are to be repeated, then docendo-discimus's super-compact code,

rep(x, (x %in% c(3,4,6,8)) * (n-1) +1)

where n may be adjusted to change the number of repetitions. If you need to call this a couple times, this could be rolled up into a function like

myReps <- function(x, y, n) rep(x, (x %in% y) * (n-1) +1)

and called as

myReps(1:10, c(3,4,6,8), 2)

in the current scenario.

lmo
  • 37,904
  • 9
  • 56
  • 69
  • 1
    This could be shortened to `rep(x, (x %in% y) * (n-1) +1)` assuming that `x` is the initial vector, `y` the elements to be repeated and `n` the number of repetitions where `n>1` – talat Apr 03 '17 at 14:46
  • This may also be a possible variation: `rep(x, (seq_along(x) %in% r) + 1)`, where `r = c(3,4,6,8)` and `x = 1:10` – d.b Apr 03 '17 at 15:13
  • @d.b, that's not correct (or only for a very specific case where x = 1:10). For example, try with `x = sample(1:10)` or `x = 16:22:` – talat Apr 03 '17 at 15:20
  • @docendodiscimus, I was (*possibly wrongly*) assuming `r` is index of the values to be repeated. But if `r` is not index, then you could just do `rep(x, (x %in% r) + 1)` – d.b Apr 03 '17 at 15:25
  • @d.b., well that would then be limited to 2 repetitions but OP wants it to be 2 or more times repeated – talat Apr 03 '17 at 15:40
4

We can try

i1 <- v1 %in% v2
sort(c(v1[!i1], rep(v1[i1], each = 2)))
#[1]  1  2  3  3  4  4  5  6  6  7  8  8  9 10

Update

For the arbitrary vector,

f1 <- function(vec1, vec2, n){
i1 <- vec1 %in% vec2
vec3 <- seq_along(vec1)
 c(vec1[!i1], rep(vec1[i1], each = n))[order(c(vec3[!i1], 
            rep(vec3[i1], each=n)))]
 }

set.seed(24)
v1N <- sample(10)
v2 <- c(3,4,6,8)
v1N
#[1]  3 10  6  4  7  5  2  9  8  1

f1(v1N, v2, 2)
#[1]  3  3 10  6  6  4  4  7  5  2  9  8  8  1
f1(v1N, v2, 3)
#[1]  3  3  3 10  6  6  6  4  4  4  7  5  2  9  8  8  8  1
akrun
  • 874,273
  • 37
  • 540
  • 662
3

Here's another approach using sapply

#DATA
x = 1:10
r = c(3,4,6,8)
n = 2 #Two repetitions of selected values

#Assuming 'r' is the index of values in x to be repeated
unlist(sapply(seq_along(x), function(i) if(i %in% r){rep(x[i], n)}else{rep(x[i],1)}))
#[1]  1  2  3  3  4  4  5  6  6  7  8  8  9 10

#Assuming 'r' is the values in 'x' to be repeated
unlist(sapply(x, function(i) if(i %in% r){rep(i, n)}else{rep(i, 1)}))
#[1]  1  2  3  3  4  4  5  6  6  7  8  8  9 10

Haven't tested these thoroughly but could be possible alternatives. Note that the order of the output will be considerably different with this approach.

sort(c(x, rep(x[x %in% r], n-1))) #assuming 'r' is values
#[1]  1  2  3  3  4  4  5  6  6  7  8  8  9 10
sort(c(x, rep(x[r], n-1))) #assuming 'r' is index
#[1]  1  2  3  3  4  4  5  6  6  7  8  8  9 10
d.b
  • 32,245
  • 6
  • 36
  • 77
  • none of your solutions work for an arbitrary vector. e.g. `x<-c(9L, 7L, 8L, 4L, 1L, 6L, 2L, 10L, 5L, 3L)`, `r <- c(3,4,6,8)` and `n<-2` – 989 Apr 04 '17 at 08:48
1

I suggest this solution just to emphasize the cool usage of append function in base R:

ff <- function(vec, v, n) {
    for(i in seq_along(v)) vec <- append(vec, rep(v[i], n-1), after = which(vec==v[i]))
    vec
}

Examples:

set.seed(1)

ff(vec = sample(10), v = c(3,4,6,8), n = 2)
#[1]  3  3  4  4  5  7  2  8  8  9  6  6 10  1

ff(vec = sample(10), v = c(2,5,9), n = 4)
#[1]  3  2  2  2  2  6 10  5  5  5  5  7  8  4  1  9  9  9  9
989
  • 12,579
  • 5
  • 31
  • 53