2

Suppose I have a list of data.frames:

list <- list(A=data.frame(x=c(1,2),y=c(3,4)), B=data.frame(x=c(1,2),y=c(7,8)))

I want to combine them into one data.frame like this:

data.frame(x=c(1,2,1,2), y=c(3,4,7,8), group=c("A","A","B","B"))
  x y group
1 1 3     A
2 2 4     A
3 1 7     B
4 2 8     B

I can do in this way:

add_group_name <- function(df, group) {
  df$group <- group
  df
}    
Reduce(rbind, mapply(add_group_name, list, names(list), SIMPLIFY=FALSE))

But I want to know if it's possible to get the name inside the lapply loop without the use of names(list), just like this:

add_group_name <- function(df) {
  df$group <- ? #How to get the name of df in the list here?
}
Reduce(rbind, lapply(list, add_group_name))
user3684014
  • 1,175
  • 12
  • 26

3 Answers3

2

I think a much easier approach is:

> do.call(rbind, lapply(names(list), function(x) data.frame(list[[x]], group = x)))
  x y group
1 1 3     A
2 2 4     A
3 1 7     B
4 2 8     B
Señor O
  • 17,049
  • 2
  • 45
  • 47
2

Using plyr:

 ldply(ll)
  .id x y
1   A 1 3
2   A 2 4
3   B 1 7
4   B 2 8

Or in 2 steps :

xx <- do.call(rbind,ll)
xx$group <- sub('([A-Z]).*','\\1',rownames(xx))
 xx
    x y group
A.1 1 3     A
A.2 2 4     A
B.1 1 7     B
B.2 2 8     B
agstudy
  • 119,832
  • 17
  • 199
  • 261
2

I renamed list to listy to remove the clash with the base function. This is a variation on Señor O's answer in essence:

do.call(rbind, Map("[<-", listy, TRUE, "group", names(listy) ) )

#    x y group
#A.1 1 3     A
#A.2 2 4     A
#B.1 1 7     B
#B.2 2 8     B

This is also very similar to a previous question and answer here: r function/loop to add column and value to multiple dataframes

The inner Map part gives this result:

Map("[<-", listy, TRUE, "group", names(listy) )

#$A
#  x y group
#1 1 3     A
#2 2 4     A
#
#$B
#  x y group
#1 1 7     B
#2 2 8     B

...which in long form, for explanation's sake, could be written like:

Map(function(data, nms) {data[TRUE,"group"] <- nms; data;}, listy, names(listy) )

As @flodel suggests, you could also use R's built in transform function for updating dataframes, which may be simpler again:

do.call(rbind, Map(transform, listy, group = names(listy)) )
Community
  • 1
  • 1
thelatemail
  • 91,185
  • 12
  • 128
  • 188