我正在尝试编写merge
的多合并替代方法,它可以将一个密钥上的两个以上数据集合并在一起。
我的代码是这样的:
multimerge <- function(..., by, all=T) {
value <- list(...)
Reduce(function(x,y)merge(x,y,by=by, all=all), value)
}
但我想要多合并的是一个列表。是否可以将list参数作为...
传递给函数?
例如:
List <- list(
data.frame('x'=c('a','b','c'), 'y'=1),
data.frame('x'=c('a','b','c'), 'z'=2)
)
需要
multimerge(List, by='x')
作为论据并给予:
x y z
a 1 2
b 1 2
c 1 2
作为输出。但我不想写另一个版本的multimerge
。
答案 0 :(得分:1)
因此,问题在于当您将列表传递到multimerge
时,列表会被放入另一个列表中,然后该列表会折叠回原始列表中。您可以检查多余的长度1列表,并剥离该级别的列表:
multimerge <- function(..., by, all=T) {
value <- list(...)
if (length(value) == 1) value <- value[[1]]
Reduce(function(x,y)merge(x,y,by=by, all=all), value)
}
答案 1 :(得分:1)
purrr
有一个名为flatten
的强大函数,可以很好地解决这个问题:
library(purrr)
multimerge <- function(..., by, all=T) {
value = flatten(list(...))
Reduce(function(x, y) merge(x, y, by=by, all=T), value)
}
无论向...
投放什么内容,flatten
都会将list(...)
转换为Reduce
的数据框列表。使用此功能,您可以提供数据帧列表,多个单独的数据帧,两者,甚至几个数据帧列表。
你也可以通过在Base R中执行类似的操作来模仿flatten
的行为:
multimerge <- function(..., by, all=T) {
value = list(...)
df_index = which(sapply(value, inherits, "data.frame"))
list_index = which(sapply(value, inherits, "list"))
value = c(value[df_index], unlist(value[list_index], recursive = FALSE))
Reduce(function(x, y) merge(x, y, by=by, all=T), value)
}
这仅将unlist
应用于&#34; list&#34;并保持数据框架不变。请注意,我使用inherits
代替is.list
,因为数据框在技术上也是列表!
<强>结果:强>
> multimerge(List, by='x')
x y z
1 a 1 2
2 b 1 2
3 c 1 2
> multimerge(List[[1]], List[[2]], by='x')
x y z
1 a 1 2
2 b 1 2
3 c 1 2
> multimerge(List, List[[1]], List[[2]], by='x')
x y.x z.x y.y z.y
1 a 1 2 1 2
2 b 1 2 1 2
3 c 1 2 1 2
> multimerge(List, List, by='x')
x y.x z.x y.y z.y
1 a 1 2 1 2
2 b 1 2 1 2
3 c 1 2 1 2
附加说明:
来自?flatten
的文档:
这些函数从列表中删除级别层次结构。它们类似于unlist(),只删除单层层次结构,并且类型稳定,因此您始终知道输出的类型是什么。
关键词是&#34; type-stability&#34;,这意味着它总是返回相同类型的数据结构。
> flatten(list(List, List[[1]], List[[2]]))
[[1]]
x y
1 a 1
2 b 1
3 c 1
[[2]]
x z
1 a 2
2 b 2
3 c 2
[[3]]
x y
1 a 1
2 b 1
3 c 1
[[4]]
x z
1 a 2
2 b 2
3 c 2
> unlist(list(List, List[[1]], List[[2]]), recursive = FALSE)
[[1]]
x y
1 a 1
2 b 1
3 c 1
[[2]]
x z
1 a 2
2 b 2
3 c 2
$x
[1] a b c
Levels: a b c
$y
[1] 1 1 1
$x
[1] a b c
Levels: a b c
$z
[1] 2 2 2
flatten
和unlist
+ recursive = FALSE
之间的主要区别在于flatten
&#34; unlists&#34;只有当输出与其余的数据结构匹配时,unlist
+ recursive = FALSE
始终将一个级别展平,所以在我的Base R示例中,我需要一个额外的步骤检查元素是列表还是数据帧。