这是一种基于 purrr 的方法:
library(purrr)
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))
result <- mylist %>%
# check whether any numbers of an element are in any of the elements
map(~map_lgl(mylist, compose(any, `%in%`), .x)) %>%
unique() %>% # drop duplicated groups
map(~reduce(mylist[.x], union)) # subset lst by group and collapse subgroups
str(result)
#> List of 3
#> $ : num 7
#> $ : num [1:8] 10 11 12 211 446 469 13 215
#> $ : num [1:5] 15 16 17 216 225
这里的逻辑与 Ronak 的回答类似;我只是觉得这更容易阅读。如果您愿意,可以将最后一行写成map(~unique(flatten_dbl(mylist[.x]))) 或拆分成map(~mylist[.x]) %>% simplify_all() %>% map(unique)。
对于哪个元素聚合到哪个组的索引,只需在用于子集的元素上调用which:
mylist %>%
map(~map_lgl(mylist, compose(any, `%in%`), .x)) %>%
unique() %>%
map(which) %>%
str()
#> List of 3
#> $ : int 1
#> $ : int [1:3] 2 3 4
#> $ : int [1:2] 5 6
整个事情的另一种逻辑是使列表嵌套而不是调用,这意味着自连接是前面的(cross2),后面没有子集,大部分函数只是设置操作:
mylist %>%
map(cross2, mylist) %>%
modify_depth(2, reduce, ~if(length(intersect(.x, .y)) > 0) sort(union(.x, .y))) %>%
map(reduce, union) %>%
unique()
或者使用cross2的.filter参数,
mylist %>%
map(cross2, mylist, ~length(intersect(.x, .y)) == 0) %>%
map(compose(sort, unique, unlist)) %>%
unique()
可以压缩成
mylist %>%
map(function(element) sort(unique(unlist(cross2(element, mylist, ~length(intersect(.x, .y)) == 0))))) %>%
unique()
不过,这些方法直到最后都不会删除重复的组,因此它们的效率可能较低。