首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >合并具有公共元素的列表

合并具有公共元素的列表
EN

Stack Overflow用户
提问于 2017-11-16 13:14:25
回答 4查看 1.6K关注 0票数 13

我有一个清单

代码语言:javascript
复制
[[1]]
[1] 7

[[2]]
[1] 10 11 12 211 446 469

[[3]]
[1] 10 11 12 13

[[4]]
[1] 11 12 13 215

[[5]]
[1] 15 16

[[6]]
[1] 15 17 216 225

我想合并具有公共元素的列表切片,并索引已合并的列表切片。我想要的输出如下所示。

代码语言:javascript
复制
$`1`
[1] 7

$`2`, `3`, `4`
[1] 10 11 12 13 211 215 446 469

$`5`,`6`
[1] 15 16 17 216 225

(我已经将原始列表切片索引作为新的列表名称,但任何形式的输出都可以。)

可重现数据:

代码语言:javascript
复制
mylist <- list(7, c(10, 11, 12, 211, 446, 469), c(10, 11, 12, 13), c(11, 
12, 13, 215), c(15, 16), c(15, 17, 216, 225))
EN

回答 4

Stack Overflow用户

发布于 2017-11-16 19:11:13

这里是使用"Matrix“和"igraph”包的另一种方法。

首先,我们需要提取连接了哪些元素的信息。使用稀疏矩阵可以节省大量内存使用:

代码语言:javascript
复制
library(Matrix)
i = rep(1:length(mylist), lengths(mylist)) 
j = factor(unlist(mylist))
tab = sparseMatrix(i = i, j = as.integer(j), x = TRUE, dimnames = list(NULL, levels(j)))
#as.matrix(tab)  ## just to print colnames
#         7    10    11    12    13    15    16    17   211   215   216   225   446   469
#[1,]  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#[2,] FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE  TRUE
#[3,] FALSE  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#[4,] FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE
#[5,] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#[6,] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE  TRUE  TRUE FALSE FALSE

查看每个元素是否相互连接:

代码语言:javascript
复制
connects = tcrossprod(tab, boolArith = TRUE)
#connects
#6 x 6 sparse Matrix of class "lsCMatrix"
#                
#[1,] | . . . . .
#[2,] . | | | . .
#[3,] . | | | . .
#[4,] . | | | . .
#[5,] . . . . | |
#[6,] . . . . | |

然后,使用图,我们可以对“mylist”的索引进行分组:

代码语言:javascript
复制
library(igraph)
# 'graph_from_adjacency_matrix' seems to not work with the "connects" object directly. 
# An alternative to coercing "connects" here would be to build it as 'tcrossprod(tab) > 0'

group = clusters(graph_from_adjacency_matrix(as(connects, "lsCMatrix")))$membership
#group
#[1] 1 2 2 2 3 3

最后,连接:

代码语言:javascript
复制
tapply(mylist, group, function(x) sort(unique(unlist(x))))
#$`1`
#[1] 7
#
#$`2`
#[1]  10  11  12  13 211 215 446 469
#
#$`3`
#[1]  15  16  17 216 225

tapply(1:length(mylist), group, toString)
#        1         2         3 
#      "1" "2, 3, 4"    "5, 6" 
票数 11
EN

Stack Overflow用户

发布于 2017-11-16 13:39:05

对解决方案不满意,但我认为这就是答案。还有改进的余地:

代码语言:javascript
复制
unique(sapply(lst, function(x) 
       unique(unlist(lst[sapply(lst, function(y) 
                         any(x %in% y))]))))


#[[1]]
#[1] 7

#[[2]]
#[1]  10  11  12 211 446 469  13 215

#[[3]]
#[1]  15  16  17 216 225

这基本上是双重循环,以检查列表元素是否存在于任何其他列表中。如果您找到任何这样的元素,那么将它们合并在一起,只从中提取unique值。

data

代码语言:javascript
复制
lst <- list(7, c(10 ,11 ,12, 211, 446, 469), c(10, 11, 12, 13),c(11 ,12, 13 ,215), 
               c(15, 16), c(15, 17 ,216 ,225))
票数 10
EN

Stack Overflow用户

发布于 2017-11-16 14:37:04

下面是一个完成任务的递归函数(尽管现在它会生成一堆警告)。

代码语言:javascript
复制
mylist <- list(7, c(10, 11, 12, 211, 446, 469), c(10, 11, 12, 13), c(11, 12, 13, 215), c(15, 16), c(15, 17, 216, 225))

commonElements = function(l,o=list(l[[1]])){
  if(length(l) == 0){return(o)}
  match = which(unlist(lapply(lapply(o,intersect,l[[1]]),any)))
  if(length(match) == 0) o[[length(o)+1]] = l[[1]]
  if(length(match) == 1) o[[match]] = unique(c(o[[match]],l[[1]]))
  if(length(match) > 1){
    o[[match[1]]] = unique(unlist(o[match]))
    p[rev(match)[-1]] = NULL
  }
  l[[1]] = NULL
  commonElements(l,o)
}

commonElements(mylist)

基本上,传入一个列表并用l的第一个元素实例化输出o。然后根据o中的每个组检查l的每个值,如果没有匹配,则在o中创建一个新元素,如果匹配,则保留唯一的集合,如果匹配超过1,则将o中的组连接起来,并删除多余的元素。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47322126

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档