首先,我希望我能想出更好的方法来描述我的问题。我正在尝试使用以下示例列表:
lst<- list(c(2), c(1,3), c(2), c(4), c(6), c(5, 7), c(6,8), c(7))
然后把它变成这样:
res<- list(c(1,2,3), c(1,2,3), c(1,2,3), c(4), c(5,6,7,8), c(5,6,7,8),c(5,6,7,8), c(5,6,7,8))
或甚至这个:
also_good_answer<- list(c(1, 2, 3), logical(0), logical(0), 4, c(5, 6, 7, 8), logical(0),
logical(0), logical(0))
我一直在使用几个
while
语句与 setdiff
组合来执行此操作,但我想知道是否有一种雄辩且更快的方法可以在一个大列表上执行此操作?
一如既往,预先感谢您。 -内特
我的方法:
lst<- list(c(2), c(1,3), c(2), c(4), c(6), c(5, 7), c(6,8), c(7)) # Original List
to_sequence<- 1:length(lst)
res<- lapply(1:length(lst), function(x) {return(NA)}) # Building Result Object
while(length(to_sequence) > 0){
tres<- c()
idx<- to_sequence[1]
next_idxs<- setdiff(lst[[idx]], NA)
tres<- c(tres, next_idxs)
while(length(next_idxs) >=1){
next_idxs<- lapply(seq_along(next_idxs), function(x){
lst[[next_idxs[x]]]
} ) %>% unlist() %>% setdiff(., unlist(tres)) # uses slow setdiff
tres<-c(tres, next_idxs)
}
res[[idx]]<- tres
to_sequence<- setdiff(to_sequence, tres) # Another slow setdiff
cat("Length to_sequence:", base::prettyNum(length(to_sequence),big.mark = ","), "\n")
}
res<- lapply(res, sort)
我不完全确定我理解问题中的处理,但以下代码不使用
setdiff
(尽管它确实使用 intersect
并且没有显式循环为示例提供相同的结果。ok
是 TRUE对于每个元素,其之前和之后的元素(之后包括元素本身)是不相交的。cumsum(ok)
给出一个逻辑分组向量,然后我们创建一个列表L
,其中包含每个组,最后重复所需的内容次数。
n <- length(lst)
ok <- sapply(seq_along(lst), function(i) {
(i == 1) || length(intersect(unlist(lst[1:(i-1)]), unlist(lst[i:n]))) == 0
})
L <- tapply(lst, cumsum(ok), function(x) sort(unique(unlist(x))))
result <- rep(L, lengths(L))
str(result)
给予
List of 8
$ 1: num [1:3] 1 2 3
$ 1: num [1:3] 1 2 3
$ 1: num [1:3] 1 2 3
$ 2: num 4
$ 3: num [1:4] 5 6 7 8
$ 3: num [1:4] 5 6 7 8
$ 3: num [1:4] 5 6 7 8
$ 3: num [1:4] 5 6 7 8