Reputation: 22352
If I want to create a named list, where I have named literals, I can just do this:
list(foo=1,bar=2,baz=3)
If instead I want to make a list with arbitrary computation, I can use lapply
, so for example:
lapply(list(1,2,3), function(x) x)
However, the list generated by lapply
will always be a regular numbered list. Is there a way I can generate a list using a function like lapply
with names.
My idea is something along the lines of:
lapply(list("foo","bar","baz"), function(key) {key=5}
==>
list(foo=5,bar=5,baz=5)
That way I don't have to have the keys and values as literals.
I do know that I could do this:
res = list()
for(key in list("foo","bar","baz") {
res[key] <- 5;
}
But I don't like how I have to create a empty list and mutate it to fill it out.
Edit: I would also like to do some computation based on the key. Something like this:
lapply(c("foo","bar","baz"), function(key) {paste("hello",key)=5})
Upvotes: 4
Views: 1344
Reputation: 9536
If you really want to set the name of the returned list elements within the code computing each value, you have to return named length-1 lists from that code instead and get rid of the outer list layer. This can readily be achieved using sapply
:
x <- list(foo=1, bar=2, baz=3)
x
#> $foo
#> [1] 1
#>
#> $bar
#> [1] 2
#>
#> $baz
#> [1] 3
sapply(names(x), function(key) setNames(list(x[[key]]^2), paste0(key, "_squared")), USE.NAMES = FALSE)
#> $foo_squared
#> [1] 1
#>
#> $bar_squared
#> [1] 4
#>
#> $baz_squared
#> [1] 9
To get a named list in the first place rlang::dots_list(..., .named=TRUE)
can sometimes be helpful (I am still searching for an equivalent in base R):
foo <- 1
bar <- 2
baz <- 3
rlang::dots_list(foo, bar, baz, .named=TRUE)
#> $foo
#> [1] 1
#>
#> $bar
#> [1] 2
#>
#> $baz
#> [1] 3
Upvotes: 0
Reputation: 312
Adapting MrFlick's use of setNames, here is a simple function that can do both:
list_zip = function(names, values) {
values = rep(values, length.out = length(names))
setNames(as.list(values), names)
}
list_zip(c("foo", "bar", "baz"), c(1,2,3))
list_zip(c("foo", "bar", "baz"), 5)
Upvotes: 0
Reputation: 206446
If your list has names in the first place, lapply will preserve them
lapply(list(a=1,b=2,c=3), function(x) x)
or you can set names before or after with setNames()
#before
lapply(setNames(list(1,2,3),c("foo","bar","baz")), function(x) x)
#after
setNames(lapply(list(1,2,3), function(x) x), c("foo","bar","baz"))
One other "option" is Map()
. Map
will try to take the names from the first parameter you pass in. You can ignore the value in the function and use it only for the side-effect of keeping the name
Map(function(a,b) 5, c("foo","bar","baz"), list(1:3))
But names cannot be changed during lapply/Map steps. They can only be copied from another location. if you need to mutate names, you'll have to do that as a separate step.
Upvotes: 3
Reputation: 52677
sapply
will use its argument for names if it is a character vector, so you can try:
sapply(c("foo","bar","baz"), function(key) 5, simplify=F)
Which produces:
$foo
[1] 5
$bar
[1] 5
$baz
[1] 5
Upvotes: 5