2

Suppose I have three vectors a.1, a.2, a.3 -- they could hold arbitrary values (meaning the values would not necessarily be sorted)

> a.1 <- seq(1,15,3)
> a.2 <- seq(15,2,-3)
> a.3 <- seq(2,15,3)
> a.1
[1]  1  4  7 10 13
> a.2
[1] 15 12  9  6  3
> a.3
[1]  2  5  8 11 14

Now I want to produce a new vector C where I take all elements of a except elements at indices 2, 3, 5 and only elements at indices 2, 3 from vector a.2 and element at index 5 from a.3; combine them in order

One way I know how to do this is:

> C <- a.1
> C[c(2,3)] <- a.2[c(2,3)]
> C[5] <- a.3[5]
> C
[1]  1 12  9 10 14

I wonder if there are are better ways of doing this -- better may include:

  1. More elegant
  2. Extendable to say splices from multiple elements
  3. More Terse (syntax wise)

Notes

  1. One of the answer authors has suggested using replace -- I wonder if replace can be used in multiway splices
  2. Also note the vales in the source or target vector need not be sorted
  3. It would be great if the same solution can be used (barring some minor modifications) on both vectors and dataframes
user1172468
  • 5,306
  • 6
  • 35
  • 62

2 Answers2

4

In this case, I'd just use a boring old loop and overwrite the corresponding indexes from each object:

multchange <- function(x, repl, idx) {
  for (i in seq_along(repl)) {
    x[idx[[i]]] <- repl[[i]][idx[[i]]]
  }
  x
}

df_list <- list(a.2, a.3)
cool_list <- list(c(2,3), 5)
multchange(a.1, df_list, cool_list)
#[1]  1 12  9 10 14

And no, using a loop is not slower on a large dataset:

samp <- rep(1:2,each=1000000)
df_list <- list(a.2, a.3)[samp]
cool_list <- list(c(2,3), 5)[samp]

system.time({
  multchange(a.1, df_list, cool_list)
})
#   user  system elapsed 
#   4.24    0.00    4.25 

c <- a.1
system.time({
  mapply(function(X, Y) { c[Y] <<- X[Y] }, X=df_list, Y=cool_list)
})
#   user  system elapsed 
#   7.46    0.00    7.49 
thelatemail
  • 91,185
  • 12
  • 128
  • 188
2
df_list <- list(a.2, a.3)
cool_list <- list(c(2,3), 5)
c <- a.1
mapply(function(X, Y) { c[Y] <<- X[Y] }, X=df_list, Y=cool_list)
AidanGawronski
  • 2,055
  • 1
  • 14
  • 24
  • Thanks for the answer -- but this assumes the vectors are sorted -- let me clarify the question – user1172468 May 30 '17 at 21:47
  • Hi, clarified the question a bit -- see if it makes sense – user1172468 May 30 '17 at 22:13
  • @user1172468 Your example is broken, and it is very unclear what your expected output is. – AidanGawronski May 30 '17 at 23:16
  • The above answer will extend to any number of vectors and "splices". – AidanGawronski May 31 '17 at 00:00
  • I'd avoid using `<<-` - if you're going to do that, just wrap a loop that does `<-` multiple times in a function and return the changed `c`. It will be far more predictable. – thelatemail May 31 '17 at 00:39
  • Everyone is so afraid of using the super assignment operator ... I like it! – AidanGawronski May 31 '17 at 00:40
  • @AidanGawronski - it's not about being afraid, it's that it can give unintended results if the function is called inside a different function. E.g. - https://stackoverflow.com/questions/9851655/why-is-using-frowned-upon-and-how-can-i-avoid-it/9851794 and https://stackoverflow.com/questions/14166207/avoiding-global-variables/14166812 for example. – thelatemail May 31 '17 at 00:42
  • Still doesn't seem like an unexpected result. Basically the fear is people use it without understanding it. – AidanGawronski May 31 '17 at 00:55
  • I didn't downvote your answer by the way if you're wondering. – thelatemail May 31 '17 at 01:24