When I'm attempting to answer this question, I noticed that row.names(x) <- vector
is not working when using lapply
on a list of data frames, while row.names<-
worked.
Here's some sample data, I'm attempting to append the names
of the list to the rownames
of the dataframes:
l <- list(a=data.frame(col = c(1,2,3),row.names = c("k","l","m")),
b=data.frame(col = c(4,5,6), row.names = c("o","p","r")))
$a
col
k 1
l 2
m 3
$b
col
o 4
p 5
r 6
For example when looping over the names
of the list and setting row.names
in lapply
, this is the result:
lapply(names(l), \(x) row.names(l[[x]]) <- paste0(x, ".", rownames(l[[x]])))
[[1]]
[1] "a.k" "a.l" "a.m"
[[2]]
[1] "b.o" "b.p" "b.r"
When we do the same code outside lapply
, it worked:
> row.names(l[["a"]]) <- paste0("a.", rownames(l[["a"]]))
> l
$a
col
a.k 1
a.l 2
a.m 3
The solution I have for this problem is to use row.names<-
(as suggested by the original OP):
setNames(lapply(names(l),
\(x) l[[x]] %>% `row.names<-` (paste(x, rownames(l[[x]]), sep = "."))),
names(l))
$a
col
a.k 1
a.l 2
a.m 3
$b
col
b.o 4
b.p 5
b.r 6
But I'm not sure why did the row.names(x) <- vector
syntax failed and why row.names<-
worked.
CodePudding user response:
The assignment is local, i.e. it creates a modified object
l
with assigned row names inside the anonymous function.The result of the
<-
assignment is returned from that anonymous function. However, the result of<-
is always the RHS, even for replacement functions. You can make this visible by putting parentheses around the assignment in the global scope:(row.names(l$a) <- paste0('a.', row.names(l$a))) # [1] "a.k" "a.l" "a.m"
So in your second piece of code, the the transformation used by lapply
is just the result of the assignment, which is the RHS of the assignment, which is the transformed row names. To fix the code, you need to return the modified object, l[[x]]
, itself:
lapply(
names(l),
\(x) {
row.names(l[[x]]) <- paste0(x, ".", row.names(l[[x]]))
l[[x]]
}
)
Or you use row.names<-
as a function call:
lapply(names(l), \(x) `row.names<-`(l[[x]], paste0(x, ".", row.names(l[[x]]))))
And to make this a bit more readable use Map
instead of lapply
:
Map(\(x, n) `row.names<-`(x, paste0(n, ".", row.names(x))), l, names(l))
Or, without anonymous function (although I’m not convinced this is more readable):
Map(`row.names<-`, l, Map(paste0, names(l), ".", Map(row.names, l)))