R函数以递归方式合并未命名的参数,输入一个列表

时间:2018-04-18 17:06:28

标签: r

我正在尝试编写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

2 个答案:

答案 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

flattenunlist + recursive = FALSE之间的主要区别在于flatten&#34; unlists&#34;只有当输出与其余的数据结构匹配时,unlist + recursive = FALSE 始终将一个级别展平,所以在我的Base R示例中,我需要一个额外的步骤检查元素是列表还是数据帧。