Home > Blockchain >  Expand a numeric vector by values
Expand a numeric vector by values

Time:04-05

Here I have a numeric vector and I would like to add val_to_add to each element and append those extra values in sample_vec, with a ceiling (max_val).

set.seed(53)

max_val = 50
val_to_add = 2

sample_vec <- sort(sample(1:max_val, 8))
[1]  3  5  6 15 29 30 35 50

For example, I want to add 2 to each element in sample_vec, so for the first element, it should be 3:(3 2), which is 3 4 5.

Duplicated values should be discarded and the maximum value in this case should be 50. The desired output is something like this:

[1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

Is there any existing function for this kind of operation maybe in base R?

CodePudding user response:

Another option with sequence:

s = sequence(rep(val_to_add   1, length(sample_vec)), sample_vec)
unique(s[s <= max_val])
#  [1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

CodePudding user response:

data

max_val = 100000
val_to_add = 100
sample_vec <- sort(sample(1:max_val, 1000)

microbenchmark

microbenchmark::microbenchmark(
  mael = {
    s = sequence(rep(val_to_add   1, length(sample_vec)), sample_vec)
    unique(s[s <= max_val])
  },
  zx_lapply = {
    s <- sort(unique(unlist(lapply(0:val_to_add, function(i) sample_vec   i))))
    s[ s <= max_val ]
  }, 
  zx_sapply = {
    s <- unique(sort(sapply(0:val_to_add, function(i) sample_vec   i)))
    s[ s <= max_val ]
  },
  grot = {
    unique(pmin(c(mapply(seq, sample_vec, sample_vec   val_to_add)), max_val))
  },
  bens = {
    out_vec <- unique(c(sapply(sample_vec, function(x) sequence(val_to_add   1, from = x))))
    out_vec[out_vec <= max_val]
  },
  check = "equal")

Unit: milliseconds
      expr     min       lq      mean   median       uq      max neval cld
      mael  8.3438  8.75930  9.604151  8.88960  9.18085  25.3535   100 a  
 zx_lapply 10.6201 10.99795 12.257785 11.12610 11.60805  48.4951   100 ab 
 zx_sapply 12.7617 13.16830 14.379648 13.32575 13.76000  26.8928   100  bc
      grot 11.7099 12.08405 16.169062 12.26395 13.25050 134.9021   100   c
      bens 14.3039 14.99095 17.444193 15.25840 17.26420 109.2186   100   c

CodePudding user response:

Make a sequence of 0 to value to add, loop, and add :

s <- sort(unique(unlist(lapply(0:val_to_add, function(i) sample_vec   i))))
s[ s <= max_val ]
#  [1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

Another option, sapply instead of lapply (thanks Benson):

s <- unique(sort(sapply(0:val_to_add, function(i) sample_vec   i)))
s[ s <= max_val ]

CodePudding user response:

Use mapply and seq to create the sequences, unravel that into a plain vector using c, take the minimum of that and max_val and then take unique elements.

unique(pmin(c(mapply(seq, sample_vec, sample_vec   val_to_add)), max_val))
## [1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

or use sapply:

sample_vec |>
  sapply(seq, length = val_to_add   1) |>
  c() |>
  pmin(max_val) |>
  unique()
##  [1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

or outer:

sample_vec |>
  outer(X = seq(0, length = val_to_add   1), FUN = ` `) |>
  c() |>
  pmin(max_val) |>
  unique()
##  [1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

Note

max_val <- 50
val_to_add <- 2
sample_vec <- c(3, 5, 6, 15, 29, 30, 35, 50)

CodePudding user response:

Here I wrap the sample_vec with a sapply to go through all elements, and use sequence to generate the desired sequence, and combine them using c().

However, I believe there are simpler solutions to it.

out_vec <- unique(c(sapply(sample_vec, function(x) sequence(val_to_add   1, from = x))))
out_vec[out_vec <= max_val]

[1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50
  • Related