Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a column to lists within a list without losing their names?

Tags:

list

r

lapply

I did several attempts to add a specific column to data frames resp. lists within a list, but all *apply() attempts failed to preserve the names of the data frames.

For example for list l,

l <- list(alpha=data.frame(1:3), bravo=data.frame(4:6), charly=data.frame(7:9))

> l
$`alpha`
  X1.3
1    1
2    2
3    3

$bravo
  X4.6
1    4
2    5
3    6

$charly
  X7.9
1    7
2    8
3    9

I want the initial letters of the lists' names as a second id column. I tried these attempts who give me basically what I want:

lapply(seq_along(l), function(x) cbind(l[[x]], id=substr(names(l)[x], 1, 1)))
# or
lapply(seq_along(l), function(x) data.frame(l[[x]], id=substr(names(l)[x], 1, 1)))
# [[1]]
# X1.3 id
# 1    1  a
# 2    2  a
# 3    3  a
# 
# [[2]]
# X4.6 id
# 1    4  b
# 2    5  b
# 3    6  b
# 
# [[3]]
# X7.9 id
# 1    7  c
# 2    8  c
# 3    9  c

but the inner lists have lost their names. Option USE.NAMES=TRUE from lapply() documentation didn't work.

I also tried these two attempts, but they failed even worse.

lapply(seq_along(l), function(x) mapply(cbind, l[[x]], id=substr(names(l)[x], 1, 1), 
                                        SIMPLIFY=FALSE))
rapply(l, function(x) cbind(x, id=substr(names(l)[x], 1, 1)), how="list")

I know I could do this like so:

l1 <- lapply(seq_along(l), function(x) cbind(l[[x]], id=substr(names(l)[x], 1, 1)))
names(l1) <- names(l)

or do a for loop:

for(i in seq_along(l)) {
  l[[i]] <- data.frame(l[[i]], id=substr(names(l)[i], 1, 1))
}

but I'd like to know whether an *apply() solution could be improved to bring the expected output, which would be:

$`alpha`
  X1.3 id
1    1  a
2    2  a
3    3  a

$bravo
  X4.6 id
1    4  b
2    5  b
3    6  b

$charly
  X7.9 id
1    7  c
2    8  c
3    9  c
like image 575
jay.sf Avatar asked Jan 01 '23 13:01

jay.sf


1 Answers

Try Map

Map(`[<-`, l, "id", value = substr(names(l), 1, 1))
#$alpha
#  X1.3 id
#1    1  a
#2    2  a
#3    3  a

#$bravo
#  X4.6 id
#1    4  b
#2    5  b
#3    6  b

#$charly
#  X7.9 id
#1    7  c
#2    8  c
#3    9  c

The first argument is a function. Map then applies the function "to the first elements of each ... argument, the second elements, the third elements, and so on.", see ?mapply.

like image 169
markus Avatar answered Jan 05 '23 04:01

markus