Reputation: 988
I want to iterate over a named list (with map), but somehow what works an a single list doesn't work at scale. What is the problem here and what do I have to change to get it working?
I suspect it has sth. to do with the difference between list[1]
and list[[1]]
but I'm missing it atm.
library(rlang)
library(tidyverse)
# this works
single_list <- list(one = 1)
create_function <- function(mylist){
function(){
x <- names(mylist)
n <- purrr::flatten_chr(mylist)
rep(x, n)
}
}
one <- create_function(single_list)
one()
#> [1] "one"
# this doesn't work
long_list <- list(one = 1,
two = 2,
three = 3)
fun <- long_list %>%
map(create_function)
fun$one()
#> Error: `.x` must be a list (double)
Upvotes: 0
Views: 1883
Reputation: 43334
When map
iterates, it automatically subsets to the contents of each element, so you're calling flatten_chr
on a numeric vector, which throws the error. Dropping the flatten_chr
call won't actually fix anything, because the names are not passed by map
, so you'll just get NULL
when you call the functions.
A good approach is to change the factory function to take two parameters, so you can iterate over both the contents and the names. purrr::imap
does this iteration automatically, so you can write
library(purrr)
create_function <- function(n, x){
function(){
rep(x, n)
}
}
list(one = 1,two = 2,three = 3) %>%
imap(create_function) %>%
map(invoke) # call each function in list
#> $one
#> [1] "one"
#>
#> $two
#> [1] "two" "two"
#>
#> $three
#> [1] "three" "three" "three"
Upvotes: 1
Reputation: 887038
The way the function was created, it needs a list
input
map(seq_along(long_list), ~ create_function(long_list[.x])())
#[[1]]
#[1] "one"
#[[2]]
#[1] "two" "two"
#[[3]]
#[1] "three" "three" "three"
Upvotes: 0