R - unlist()中的名称连接分隔符(展平列表列表)

时间:2016-05-29 18:45:01

标签: r list naming internal separator

可以使用unlist(list, recursive = FALSE)展开列表列表,如this问题所示。此操作使用默认点(.)分隔符连接列表名称,这是R中变量命名的标准。一个简单的示例说明了这一点:

# Create example list, l
> l <- list("a" = list("x" = 1, "y" = 2), "b" = list("x" = 3, "y" = 4))

> l
$a
$a$x
[1] 1

$a$y
[1] 2


$b
$b$x
[1] 3

$b$y
[1] 4

# Unlist lists in l
> l.unlisted <- unlist(l, recursive = FALSE)

> l.unlisted
$a.x
[1] 1

$a.y
[1] 2

$b.x
[1] 3

$b.y
[1] 4

尽管有标准命名约定,但我希望名称具有不同的分隔符(_)。通过使用sub来查找和替换每个名称中的默认.分隔符,并在unlist()中进行了一次连接后,可以通过字符串操作来执行此操作,如下所示:

> names(l.unlisted) <- sub('.', '_', names(l.unlisted), fixed=TRUE)

> l.unlisted
$a_x
[1] 1

$a_y
[1] 2

$b_x
[1] 3

$b_y
[1] 4

虽然这在大多数情况下已经足够,但我认为可以通过更改unlist()使用的默认分隔符来消除额外的连接步骤。我假设这可以通过使用fix()添加sep参数来改变函数的源代码来完成,类似于paste()中使用的参数。但是,我不知道该怎么做,因为unlist()是一个内部函数。

有没有办法改变unlist()中的默认名称连接分隔符,如何做到这一点?

1 个答案:

答案 0 :(得分:0)

虽然可以按照akrun的注释中的建议搜索替换点,但这是一种黑客解决方案,如果名称中已经包含点,则不一定有效。这是一个更强大的解决方案。

示例列表:

ex_list = list(
  a = c(x1=1, x2=2, x3=3),
  b = c(y1=1, y2=2),
  c = c(z1=1)
)

看起来像:

> ex_list
$a
x1 x2 x3 
 1  2  3 

$b
y1 y2 
 1  2 

$c
z1 
 1 

常用方法:

> #tries
> unlist(ex_list)
a.x1 a.x2 a.x3 b.y1 b.y2 c.z1 
   1    2    3    1    2    1 
> do.call(what = c, args = ex_list)
a.x1 a.x2 a.x3 b.y1 b.y2 c.z1 
   1    2    3    1    2    1 
> unlist(unname(ex_list))
x1 x2 x3 y1 y2 z1 
 1  2  3  1  2  1 

前两个使用点(.)分隔符进行连接,第三个不使用前缀(在某些情况下有用)。

一个功能:

#with custom separator
unlist2 = function(x, sep = "_") {
  #save top names
  top_names = names(x)
  x = unname(x)

  #flatten
  x2 = unlist(x)

  #add prefix
  #determine how many prefixes to add of each
  lengths_top = sapply(x, length)
  prefixes = rep(top_names, times = lengths_top)
  names(x2) = paste0(prefixes, sep, names(x2))

  x2
}

测试:

> #tests
> unlist2(ex_list)
a_x1 a_x2 a_x3 b_y1 b_y2 c_z1 
   1    2    3    1    2    1 
> unlist2(ex_list, sep = "-")
a-x1 a-x2 a-x3 b-y1 b-y2 c-z1 
   1    2    3    1    2    1 

基数R unlist()

基本的R函数调用.Internal,因此我们不能轻易对其进行修改:

> unlist
function (x, recursive = TRUE, use.names = TRUE) 
{
    if (.Internal(islistfactor(x, recursive))) {
        lv <- unique(.Internal(unlist(lapply(x, levels), recursive, 
            FALSE)))
        nm <- if (use.names) 
            names(.Internal(unlist(x, recursive, use.names)))
        res <- .Internal(unlist(lapply(x, as.character), recursive, 
            FALSE))
        res <- match(res, lv)
        structure(res, levels = lv, names = nm, class = "factor")
    }
    else .Internal(unlist(x, recursive, use.names))
}
<bytecode: 0x558a410998b0>
<environment: namespace:base>

根据.Internal的文档:

  

只有真正的R向导甚至应该考虑使用此功能,并且仅   R开发人员可以将其添加到内部函数列表中。