0

I have list of data.frames.

> LoDFs <- list(data.frame(y1=c(1,2,3), y2=c(4,5,6)), data.frame(yA=c(1,2,3), yB=c(4,5,6)))

> LoDFs
[[1]]
  y1 y2
1  1  4
2  2  5
3  3  6

[[2]]
  yA yB
1  1  4
2  2  5
3  3  6

Here I've found how to use lapply function to manipulate each data.frame separately. My goal is to change the column names in particular data.frame (both data.frames should have first column named A and second B). I've tried following:

> col.names <- c("A", "B")
> lapply(seq_along(LoDFs), function(x) {colnames(LoDFs[[x]]) <- col.names})
[[1]]
[1] "A" "B"

[[2]]
[1] "A" "B"

But it just returns the modification and didn't affect the particular data.frame:

> LoDFs
[[1]]
  y1 y2
1  1  4
2  2  5
3  3  6

[[2]]
  yA yB
1  1  4
2  2  5
3  3  6

How to save the modifications which *apply family of functions did on data?

Community
  • 1
  • 1
Wakan Tanka
  • 7,542
  • 16
  • 69
  • 122
  • 1
    same issue as [this](http://stackoverflow.com/questions/36307870/r-function-which-has-a-data-frame-parameter-doesnt-work) about four questions down? – rawr Mar 30 '16 at 12:01
  • @rawr can you please modify mentioned example to my problem and post it as an answer? Based on linked question/answer I've tried to return value from function `lapply(seq_along(LoDFs), function(x) {colnames(LoDFs[[x]]) <- col.names; LoDFs})` but it did not worked as expected. – Wakan Tanka Mar 30 '16 at 12:54
  • 1
    You have the right idea, but since lapply is acting on individual elements of LoDFs, you need to return that structure for each iteration. if you just have `; LoDFs})`, the replacement will be the entire list _for each iteration_. so you just need to return the modified elements `; LoDFs[[x]]})` – rawr Mar 30 '16 at 13:14
  • Guys I've up voted all answers and comments (but I can only pick up one answer). Seems that assigning results back to the variable is the only way. Thank you – Wakan Tanka Mar 30 '16 at 21:48

2 Answers2

1
lapply(LoDFs, 'names<-', c("A", "B"))
[[1]]
  A B
1 1 4
2 2 5
3 3 6

[[2]]
  A B
1 1 4
2 2 5
3 3 6
Pierre L
  • 28,203
  • 6
  • 47
  • 69
  • This is basically correct, BUT it is necessary to assign the result to old variable e.g. `LoDFs <- lapply(LoDFs, 'names<-', c("A", "B"))`. I'm wondering if it is possible modify the data in place from `*apply`. – Wakan Tanka Mar 30 '16 at 12:54
  • 1
    @WakanTanka if you try the code you suggested you should find that it works. Any assignment in R can happen in place – Chris Mar 30 '16 at 19:42
  • @Chris yes it works, but I was wondering if it is possible directly from `*apply` function without overwriting original variable. – Wakan Tanka Mar 30 '16 at 21:43
  • It is not overwriting anything. The original list is intact. – Pierre L Mar 30 '16 at 21:47
  • @PierreLafortune pardon my ignorance but I do not know what you mean. In your example when you print (without assigning) `LoDFs` then you can see that column names are the same as before. I would like to ask what does this `'names<-'` mean? Thank you very much. – Wakan Tanka Mar 30 '16 at 21:51
1

Another option is setNames

lapply(LoDFs, setNames, c('A', 'B'))
# [[1]]
#  A B
#1 1 4
#2 2 5
#3 3 6

#[[2]]
#  A B
#1 1 4
#2 2 5
#3 3 6

If we need to modify in place, we can use %<>% operator from magrittr.

library(magrittr)
LoDFs %<>% 
      lapply(., setNames, c("A", "B"))
sapply(LoDFs, names)
#    [,1] [,2]
#[1,] "A"  "A" 
#[2,] "B"  "B" 
akrun
  • 874,273
  • 37
  • 540
  • 662
  • This is basically correct, BUT it is necessary to assign the result to old variable e.g. `LoDFs <- lapply(LoDFs, setNames, c('A', 'B'))`. I'm wondering if it is possible modify the data in place from `*apply`. – Wakan Tanka Mar 30 '16 at 12:54
  • @WakanTanka Updated the post. Hope it helps – akrun Mar 30 '16 at 12:58
  • Seems that `magrittr` solution is similar to previous. This is first time I see `magrittr` code so maybe I'm wrong but the "magic" here lies in using `%<>%` instead of `>%` which basically assigns the result back to the left operand or am I wrong? – Wakan Tanka Mar 30 '16 at 21:46