将一个向量列表合并为单个向量

63

我有一个数字向量的列表,我想将它们合并成一个向量。但我无法做到这一点。该列表中的元素可能有一个公共元素。最终向量不应重复添加它们。以下是一个例子:

>lst
`1`
[1] 1 2
`2`
[2] 2 4 5
`3`
[3] 5 9 1

我希望您能翻译成这种最终结果

>result
[1] 1 2 4 5 9 1

我尝试做以下的事情,不用担心重复:

>vec<-vector()
>sapply(lst, append,vec)

>vec<-vector()
>sapply(lst, c, vec)

它们都没用。有人可以帮我吗?

谢谢。


谢谢@JoshO'Brien。但这并没有删除重复的值。 - Rachit Agrawal
@joran 我怀疑 unique 不够细粒度;unique 很容易删除相邻列表组件之间的超过1个共同元素。请注意,unique(unlist(lst)) 不能得到 OP 想要的结果。 - Gavin Simpson
3
你是在说你不希望任何重复的值紧挨在一起吗?还是说,如果一个向量的结尾与下一个向量的开头匹配,你只是不想重复一个元素?提供更多的例子可能会有所帮助... - Dason
2
@JoshO'Brien unique() 会剥夺掉一个 1,而原帖中声称输出结果应该包含这个 1 - Gavin Simpson
2
这个代码可以工作,但如果列表元素内有重复值,我就不确定它是否能正常工作:unique(do.call(c, lst))。根据@MatthewLundberg的教义,使用rle(do.call(c, lst))$values。根据我的基准测试,Matthew的解决方案更快。 - Roman Luštrik
6个回答

59

比上面提出的解决方案更快的解决方案:

vec<-unlist(lst)
vec[which(c(1,diff(vec)) != 0)]

6
vec[which(c(1,diff(vec)) != 0)] 是什么意思? 它的作用是选择向量 vec 中所有不重复的元素。 - Galaxy
4
它比上面提出的那个更快吗? - hedgedandlevered
2
@Galaxy 这是用于删除连续重复项,同时保留被其他元素分隔的重复元素。diff() 函数将前一个值减去当前值。如果 diff(vec) 等于零,则表示当前值和前一个值相同,可以将此值删除。例如,使用 lst <- list(c(1,2),c(2,4,5),c(5,9,1))vec<-unlist(lst),则 vec[which(c(1,diff(vec)) != 0)] 将删除所有连续重复项,但会保留最后一个重复项。 - Paul Rougieux

25
另一个使用Reduce()的答案。
创建向量列表:
lst <- list(c(1,2),c(2,4,5),c(5,9,1))

将它们合并为一个向量

vec <- Reduce(c,lst)
vec
# [1] 1 2 2 4 5 5 9 1

仅保留重复的内容一次:

unique(Reduce(c,lst))
#[1] 1 2 4 5 9
如果您想保留末尾的重复值,您可能需要使用vec[which(c(1,diff(vec)) != 0)],就像@Rachid的回答中所示。

2
事实上,“unlist(lst)”比“Reduce(c,lst)”更容易。 - Paul Rougieux

8

您需要RLE算法:

rle(unlist(lst))$values

> lst <- list(`1`=1:2, `2`=c(2,4,5), `3`=c(5,9,1))
> rle(unlist(lst))$values
## 11 21 22 31 32 33 
##  1  2  4  5  9  1 

我也在考虑这个问题。我唯一的问题是,我不知道他们是否想要删除列表元素中重复的值... - Dason
2
这实现了我想做的事情。我也可以使用以下选项完成: vec<-unlist(lst); vec[which(c(1,diff(vec)) != 0)] 现在我在想哪个更好? - Rachit Agrawal
那可能更快,因为它做的工作更少(在我的机器上在你的简单示例上也更快)。查看“rle”的代码。你可以将其作为另一个答案添加进去。 - Matthew Lundberg
@MatthewLundberg 你是如何计算时间的? - Rachit Agrawal

7

使用栈也可以很好地完成此操作,并且看起来更加简洁:

stack(lst)$values

4

通过对RachitMartijn的两个答案进行基准测试。

rbenchmark::benchmark(
  "unlist" = {
    vec<-unlist(a)
    vec[which(diff(vec) != 0)]
  },
  "reduce" = {
    a %>% reduce(c) %>% unique
  }
)

输出:

    test replications elapsed relative user.self sys.self user.child sys.child
2 reduce          100   0.036        3     0.036    0.000          0         0
1 unlist          100   0.012        1     0.000    0.004          0         0

这个答案 明显胜过另一个。


3

采用tidyverse的方法:

library(tidyverse)
lst %>% reduce(c) %>% unique

这里使用了 purrr 中的(小写)reduce 版本与管道组合。同时需要注意,如果列表包含命名向量,则根据使用 unlist 还是 reduce 方法,最终的命名将有所不同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接