减少不同长度的嵌套列表
Reduce a nested list with varying length
假设我有一个列表:
mylist=list(list(data.frame(a=3,b=2,c=4),data.frame(d=5,e=6,h=8),data.frame(k=2,e=3,b=5,m=5)),
list(data.frame(a=32,b=22,c=42),data.frame(d=5,e=63,h=82),data.frame(k=2,e=33,b=5,m=5)),
list(data.frame(a=33,b=21,k=41,c=41),data.frame(d=5,e=61,h=80),data.frame(k=22,e=3,b=5,m=5)))
然后我尝试通过 cbind
列表的每个元素来获取一个新列表,例如 cbind mylist[[1]][[1]]
withmylist[[2]][[1]]
andmylist[[3]][[1]]
函数:
newlist=lapply(seq_along(mylist[[1]]), function(x){
newlist=Reduce("cbind",c(mylist[[1]][x],mylist[[-1]][x]))
return(newlist)
})
I get:
Error in mylist[[-1]] : attempt to select more than one element
但如果列表只有:
,则 lapply 有效
mylistshort=mylist[-3]
期望的结果是:
[[1]]
a b c a b c a b k c
1 3 2 4 32 22 42 33 21 41 41
[[2]]
d e h d e h d e h
1 5 6 8 5 63 82 5 61 80
[[3]]
k e b m k e b m k e m
1 2 3 5 5 2 33 5 5 22 3 5
那么如何减少长度大于 2 的列表?
最好的问候
这是一种使用老式 do.call()
而不是 Reduce()
的方法。
lapply(
seq_along(mylist),
function(ii) do.call(cbind, vapply(mylist, "[", list(1), ii))
)
# [[1]]
# a b c a b c a b k c
# 1 3 2 4 32 22 42 33 21 41 41
#
# [[2]]
# d e h d e h d e h
# 1 5 6 8 5 63 82 5 61 80
#
# [[3]]
# k e b m k e b m k e b m
# 1 2 3 5 5 2 33 5 5 22 3 5 5
您按照 Ananda Mahto 的建议执行以下操作(使用 Reduce
):
myfun <- function(x) Reduce(cbind,x)
apply(do.call(cbind, mylist), 1, myfun)
我的原回答(包括data.table
)
require(data.table)
setDT(mylist)
myfun <- function(x) Reduce(cbind,x)
apply(mylist,1, myfun)
结果:
> apply(mylist,1, myfun)
[[1]]
a b c a b c a b k c
1 3 2 4 32 22 42 33 21 41 41
[[2]]
d e h d e h d e h
1 5 6 8 5 63 82 5 61 80
[[3]]
k e b m k e b m k e b m
1 2 3 5 5 2 33 5 5 22 3 5 5
另一种方法是使用 unlist
,如下所示:
un_mylist <- unlist(mylist, recursive = FALSE)
ind <- lapply(seq_along(mylist), seq, to = length(un_mylist), by = length(mylist))
myfun <- function(ind, x){
Reduce(cbind,x[ind])
}
lapply(ind, myfun, x = un_mylist)
此方法假设所有嵌套列表都具有相同的长度:
sapply(mylist, length)
另一个想法:
.mapply(cbind, mylist, NULL)
#[[1]]
# a b c a b c a b k c
#1 3 2 4 32 22 42 33 21 41 41
#
#[[2]]
# d e h d e h d e h
#1 5 6 8 5 63 82 5 61 80
#
#[[3]]
# k e b m k e b m k e b m
#1 2 3 5 5 2 33 5 5 22 3 5 5
编辑: 一些评论
您基本上是在寻找 "vectorised" cbind
。您可以为此使用 for
循环,但 R 有一个内置的 "vectorisation" 工具:mapply
(不一定更快,但更清洁)。对于特定数量的参数,您可以使用 mapply
,如下所示:
mapply(function(x, y, z) cbind(x, y, z), mylist[[1]], mylist[[2]], mylist[[3]])
但是,您也可以传递一个 "variable-length arguments" (...
) 以使其更实用:
mapply(function(...) cbind(...), mylist[[1]], mylist[[2]], mylist[[3]])
cbind
旨在了解如何处理 ...
个参数:
mapply(cbind, mylist[[1]], mylist[[2]], mylist[[3]])
这仍然不灵活,因为您必须指定每个参数,因为 mapply
只接受 ...
。 do.call
对于在 "list":
中有函数参数的情况很方便
do.call(mapply, c(cbind, mylist))
R,有一个带点的 mapply
接受其 ...
参数作为列表,看起来更酷,并且可以替换 do.call
:
.mapply(FUN = cbind, dots = mylist, MoreArgs = NULL)
假设我有一个列表:
mylist=list(list(data.frame(a=3,b=2,c=4),data.frame(d=5,e=6,h=8),data.frame(k=2,e=3,b=5,m=5)),
list(data.frame(a=32,b=22,c=42),data.frame(d=5,e=63,h=82),data.frame(k=2,e=33,b=5,m=5)),
list(data.frame(a=33,b=21,k=41,c=41),data.frame(d=5,e=61,h=80),data.frame(k=22,e=3,b=5,m=5)))
然后我尝试通过 cbind
列表的每个元素来获取一个新列表,例如 cbind mylist[[1]][[1]]
withmylist[[2]][[1]]
andmylist[[3]][[1]]
函数:
newlist=lapply(seq_along(mylist[[1]]), function(x){
newlist=Reduce("cbind",c(mylist[[1]][x],mylist[[-1]][x]))
return(newlist)
})
I get:
Error in mylist[[-1]] : attempt to select more than one element
但如果列表只有:
,则 lapply 有效mylistshort=mylist[-3]
期望的结果是:
[[1]]
a b c a b c a b k c
1 3 2 4 32 22 42 33 21 41 41
[[2]]
d e h d e h d e h
1 5 6 8 5 63 82 5 61 80
[[3]]
k e b m k e b m k e m
1 2 3 5 5 2 33 5 5 22 3 5
那么如何减少长度大于 2 的列表? 最好的问候
这是一种使用老式 do.call()
而不是 Reduce()
的方法。
lapply(
seq_along(mylist),
function(ii) do.call(cbind, vapply(mylist, "[", list(1), ii))
)
# [[1]]
# a b c a b c a b k c
# 1 3 2 4 32 22 42 33 21 41 41
#
# [[2]]
# d e h d e h d e h
# 1 5 6 8 5 63 82 5 61 80
#
# [[3]]
# k e b m k e b m k e b m
# 1 2 3 5 5 2 33 5 5 22 3 5 5
您按照 Ananda Mahto 的建议执行以下操作(使用 Reduce
):
myfun <- function(x) Reduce(cbind,x)
apply(do.call(cbind, mylist), 1, myfun)
我的原回答(包括data.table
)
require(data.table)
setDT(mylist)
myfun <- function(x) Reduce(cbind,x)
apply(mylist,1, myfun)
结果:
> apply(mylist,1, myfun)
[[1]]
a b c a b c a b k c
1 3 2 4 32 22 42 33 21 41 41
[[2]]
d e h d e h d e h
1 5 6 8 5 63 82 5 61 80
[[3]]
k e b m k e b m k e b m
1 2 3 5 5 2 33 5 5 22 3 5 5
另一种方法是使用 unlist
,如下所示:
un_mylist <- unlist(mylist, recursive = FALSE)
ind <- lapply(seq_along(mylist), seq, to = length(un_mylist), by = length(mylist))
myfun <- function(ind, x){
Reduce(cbind,x[ind])
}
lapply(ind, myfun, x = un_mylist)
此方法假设所有嵌套列表都具有相同的长度:
sapply(mylist, length)
另一个想法:
.mapply(cbind, mylist, NULL)
#[[1]]
# a b c a b c a b k c
#1 3 2 4 32 22 42 33 21 41 41
#
#[[2]]
# d e h d e h d e h
#1 5 6 8 5 63 82 5 61 80
#
#[[3]]
# k e b m k e b m k e b m
#1 2 3 5 5 2 33 5 5 22 3 5 5
编辑: 一些评论
您基本上是在寻找 "vectorised" cbind
。您可以为此使用 for
循环,但 R 有一个内置的 "vectorisation" 工具:mapply
(不一定更快,但更清洁)。对于特定数量的参数,您可以使用 mapply
,如下所示:
mapply(function(x, y, z) cbind(x, y, z), mylist[[1]], mylist[[2]], mylist[[3]])
但是,您也可以传递一个 "variable-length arguments" (...
) 以使其更实用:
mapply(function(...) cbind(...), mylist[[1]], mylist[[2]], mylist[[3]])
cbind
旨在了解如何处理 ...
个参数:
mapply(cbind, mylist[[1]], mylist[[2]], mylist[[3]])
这仍然不灵活,因为您必须指定每个参数,因为 mapply
只接受 ...
。 do.call
对于在 "list":
do.call(mapply, c(cbind, mylist))
R,有一个带点的 mapply
接受其 ...
参数作为列表,看起来更酷,并且可以替换 do.call
:
.mapply(FUN = cbind, dots = mylist, MoreArgs = NULL)