Reputation: 73397
I've learned about the replace
function that could become my friend
dat1 <- data.frame(matrix(1:12, 3, 4))
rpl <- c(2, 4, 1)
t(sapply(seq_along(rpl), function(x) replace(dat1[x, ], rpl[x], NA)))
# X1 X2 X3 X4
# [1,] 1 NA 7 10
# [2,] 2 5 8 NA
# [3,] NA 6 9 12
but I didn't get it to work in more complex replacement situations:
(M <- structure(c(3L, 9L, 14L, 16L, 6L, 8L, 10L, 15L, 1L, 4L, 11L,
13L, 2L, 5L, 7L, 12L), .Dim = c(4L, 4L), .Dimnames = list(NULL,
NULL)))
# [,1] [,2] [,3] [,4]
# [1,] 3 6 1 2
# [2,] 9 8 4 5
# [3,] 14 10 11 7
# [4,] 16 15 13 12
dat2 <- data.frame(x=matrix(NA, 16))
> sapply(1:4, function(j) replace(dat2$x, M[, j], j))
[,1] [,2] [,3] [,4]
[1,] NA NA 3 NA
[2,] NA NA NA 4
[3,] 1 NA NA NA
[4,] NA NA 3 NA
[5,] NA NA NA 4
[6,] NA 2 NA NA
[7,] NA NA NA 4
[8,] NA 2 NA NA
[9,] 1 NA NA NA
[10,] NA 2 NA NA
[11,] NA NA 3 NA
[12,] NA NA NA 4
[13,] NA NA 3 NA
[14,] 1 NA NA NA
[15,] NA 2 NA NA
[16,] 1 NA NA NA
The results are distributed in a matrix instead of changing just the column, whereas the for
loop or the sapply
give me what I want:
for (j in 1:4) dat2$x[M[, j]] <- j
# or
sapply(1:4, function(j) dat2$x[M[, j]] <<- j)
> dat3
x
1 3
2 4
3 1
4 3
5 4
6 2
7 4
8 2
9 1
10 2
11 3
12 4
13 3
14 1
15 2
16 1
How can I properly use replace
in this / such a more complex case?
BTW, why does <<-
have such a bad reputation even though it fulfills its purpose, at least in this case? (Or is it just a thinking problem because I've "heard" something??). Is there an example where it's really bad practice, if it is not being used in a function that accidentally destroys something in the global environment?
Upvotes: 4
Views: 70
Reputation: 269905
This isn't a problem with replace
. The problem is that sapply
works in parallel (not in the sense of paraellel processing but just conceptually) rather than applying one iteration on the result of the prior iteration. To do that use Reduce
.
transform(dat2, x = Reduce(function(x, i) replace(x, M[, i], i), init = x, 1:ncol(M)))
Upvotes: 1