Can someone explain to me why this gives an error using purrr:
map(list(list(a=1, b=2, c=3), list(a=1, b=2, c=3)), `[[<-`, "b", 1)
but the same call with lapply seems to work.
I was under the impression that [[<- was just a function call, so was expecting both purrr and lapply to do the same thing here.
The issue lies in purrr::as_mapper(), which map() calls under the hood. Consider the difference:
x <- list( a=1, b=2, c=3 )
`[[<-`( x, "b", 1 ) # This is what lapply() calls
# x is unchanged, returns modified list
purrr::as_mapper(`[[<-`)( x, "b", 1 ) # This is what map() calls
# x is modified in-place, returns value 1
The second function call behaves as if you typed the following assignment expression:
(x[["b"]] <- 1)
# [1] 1
which must be causing issues when the function is passed down to map() internals. Interestingly, wrapping the function with a ~ lambda works, but returns the "wrong" result:
y <- list(list(a=1, b=2, c=3), list(a=1, b=2, c=3))
purrr::map( y, ~purrr::as_mapper(`[[<-`)(.x, "b", 1) )
# [[1]]
# [1] 1
# [[2]]
# [1] 1
purrr::map( y, purrr::as_mapper(`[[<-`), "b", 1 )
# Error in list(a = 1, b = 2, c = 3)[["b"]] <- 1 :
# target of assignment expands to non-language object
The proper purrr equivalents to your lapply() example would instead look something like this:
r1 <- lapply(y, `[[<-`, "b", 1)
r2 <- purrr::map(y, purrr::modify_at, "b", ~1)
r3 <- purrr::map(y, ~`[[<-`(.x, "b", 1))
identical( r1, r2 ) # TRUE
identical( r1, r3 ) # TRUE
In the above, modify_at() returns the modified list, just like [[<-(...) does, and the tilde ~ is needed because modify_at() expects a function. The alternative is to wrap `[[<-` into a ~ lambda.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With