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