Name list elements based on variable names R
Asked Answered
T

3

17

I want to add elements to an empty list on the fly. Each element in the list should be named automatically after a set of variables which value will vary.

However, I cannot seem to find a way to name list elements on the fly without getting errors. Consider the example below:

L <- list()

var1 <- "wood"
var2 <- 1.0
var3 <- "z4"

varname <- paste(var1, as.character(var2), var3, sep="_")

# This works fine:
L$"wood_1_z4" <- c(0,1)
L$"wood_1_z4"
0 1

# This doesn't!!
L$paste(var1, as.character(var2), var3, sep="_") <- c(0,1)
Error in L$paste(var1, as.character(var2), var3, sep = "_") <- c(0, 1) : 
  invalid function in complex assignment

# Ths doesn't either ... 
L$eval(parse(text = "varname")) <- c(0,1)
Error in L$eval(parse(text = "varname")) <- c(0, 1) : 
target of assignment expands to non-language object

Is there a way to do this?

Tongue answered 20/5, 2015 at 13:57 Comment(3)
Use [[: L[[paste(var1, as.character(var2), var3, sep="_")]]<-c(0,1)Flexure
What about if you assign values to names(L)?Rollick
$ doesn't do any evaluation on the right hand side, hence the errors.Wisdom
P
14

You cannot assign to paste() using the <- operator (and I believe this is true for the eval() function as well). Instead, you need to either use the [[ operator or use the names() function. You can do this like so:

L <- list()
var1 <- "wood"
var2 <- 1.0
var3 <- "z4"
varname <- paste(var1, as.character(var2), var3, sep="_")

# Using [[
L[[varname]] <- c(0,1)

> L
$wood_1_z4
[1] 0 1

# Using names()
L[[1]] <- c(0,1)
names(L)[1] <- varname

> L
$wood_1_z4
[1] 0 1

A more effective way to do this might be to use a function that both creates the value and names the list element, or even one that just creates the value - if you then use sapply you can name each list element using arguments from the call to your function and the USE.NAMES options.

In a general sense, R isn't really well-optimized for growing lists over time when the final size and structure of the list aren't well-known. While it can be done, a more "R-ish" way to do it would be to figure out the structure ahead of time.

Paint answered 20/5, 2015 at 14:22 Comment(1)
While it's true that you can't assign to paste and eval, the reason why it isn't working is because the primitive $ doesn't evaluate on the right hand side. Per the comments in the C code for $: "We need to be sure to only evaluate the first argument. The second will be a symbol that needs to be matched, not evaluated."Wisdom
S
5

An alternative would be to use the wrapper setNames() from the stats package, like so:

var1 <- "wood"
var2 <- 1.0
var3 <- "z4"
varname <- paste(var1, as.character(var2), var3, sep="_")

L <- setNames(list(c(0, 1)), varname)

> L
$wood_1_z4
[1] 0 1 
Saintsimon answered 4/5, 2021 at 17:1 Comment(0)
K
1

Use the `names<-` infix operator as a normal function to return a named list. Then use c() to concatenate this with the list L. This one-liner can be used to continue to add elements to L 'on the fly' as requested.

L <- list()
var1 <- "wood"
var2 <- 1.0
var3 <- "z4"
varname <- paste(var1, as.character(var2), var3, sep="_")

L <- c(L, `names<-`(list(c(0, 1)), varname))

L
#> $wood_1_z4
#> [1] 0 1
Knick answered 10/12, 2021 at 16:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.