所有子集的所有N个组合

6

给定一个元素向量,我想要得到所有可能的子集长度为n的组合的列表。例如,对于(最简单的)序列1:2,我想要获得形式如下的列表对象:

{ {{1},{1}}, {{1},{2}}, {{2},{2}}, {{1},{1,2}}, {{2},{1,2}}, {{1,2},{1,2}} }

n=2 时。

我能够使用以下方法生成所有非空子集的列表:

listOfAllSubsets <- function (s) {
  n <- length(s)
  unlist(lapply(1:n, function (n) {
    combn(s, n, simplify=FALSE)
  }), recursive=FALSE)
}

然而,我不确定从这里开始的最佳方法。本质上,我想要将这个列表与其自身进行笛卡尔积(对于n=2)。

有什么建议吗?最好是非迭代解决方案(即没有for循环)。


1
expand.grid 是获取笛卡尔积的一种方法。顺便说一下,它似乎忽略了空子集。 - Frank
3个回答

3

从索引的笛卡尔积开始会更容易。然后通过确保索引元组已排序来避免重复。

combosn <- function(items,n) {
  i <- seq_along(items)
  idx <-do.call(expand.grid,rep(list(i),n))
  idx <- idx[!apply(idx,1,is.unsorted),]
  apply(idx,1,function(x) items[x])
}

ss<-listOfAllSubsets(1:2)

str(combosn(ss,2))
6个列表
 $ :2个元素的列表
  ..$ : 整数 1
  ..$ : 整数 1
 $ :2个元素的列表
  ..$ : 整数 1
  ..$ : 整数 2
 $ :2个元素的列表
  ..$ : 整数 2
  ..$ : 整数 2
 $ :2个元素的列表
  ..$ : 整数 1
  ..$ : 由1和2组成的整数序列
 $ :2个元素的列表
  ..$ : 整数 2
  ..$ : 由1和2组成的整数序列
 $ :2个元素的列表
  ..$ : 由1和2组成的整数序列
  ..$ : 由1和2组成的整数序列

或者,对于n=3

str(combosn(ss,3))

Translated result:
名单10 $ :3名单 ..$ :整数1 ..$ :整数1 ..$ :整数1 $ :3名单 ..$ :整数1 ..$ :整数1 ..$ :整数2 $ :3名单 ..$ :整数1 ..$ :整数2 ..$ :整数2 $ :3名单 ..$ :整数2 ..$ :整数2 ..$ :整数2 $ :3名单 ..$ :整数1 ..$ :整数1 ..$ :整数[1:2] 1 2 $ :3名单 ..$ :整数1 ..$ :整数2 ..$ :整数[1:2] 1 2 $ :3名单 ..$ :整数2 ..$ :整数2 ..$ :整数[1:2] 1 2 $ :3名单 ..$ :整数1 ..$ :整数[1:2] 1 2 ..$ :整数[1:2] 1 2 $ :3名单 ..$ :整数2 ..$ :整数[1:2] 1 2 ..$ :整数[1:2] 1 2 $ :3名单 ..$ :整数[1:2] 1 2 ..$ :整数[1:2] 1 2 ..$ :整数[1:2] 1 2

+1 不错的技巧!这正是我正在寻找的。不过,您能否将您的答案扩展到n长度组合?那是我的原始问题,从您所提供的(2元组)推广并不明显。 - merv
泛化在我对一个相关问题的答案中,但我会尝试在这里加以说明。 - A. Webb
1
实际上,这对你的问题来说是过于概括了。关键是要过滤掉由expand.grid创建的未排序索引。 - A. Webb

2
这是我会做的事情,例如,使用s=1:2

1)为每个元素的成员身份表示子集的0/1矩阵。

subsets = as.matrix(do.call(expand.grid,replicate(length(s),0:1,simplify=FALSE)))

这提供了

     Var1 Var2
[1,]    0    0
[2,]    1    0
[3,]    0    1
[4,]    1    1

这里,第一行是空子集;第二行是{1};第三行是{2};第四行是{1,2}。要获取子集本身,请使用 mysubset = s[subsets[row,]],其中row是你想要的子集所在的行。

2) 将子集对表示为矩阵的行对:

pairs <- expand.grid(Row1=1:nrow(subsets),Row2=1:nrow(subsets))

这提供了

   Row1 Row2
1     1    1
2     2    1
3     3    1
4     4    1
5     1    2
6     2    2
7     3    2
8     4    2
9     1    3
10    2    3
11    3    3
12    4    3
13    1    4
14    2    4
15    3    4
16    4    4

这里,第14行对应于subsets的第二行和第四行,因此是{1}和{1,2}。这假定了对组合的顺序有所考虑(在进行笛卡尔积时隐含了这一点)。要恢复子集,请使用mypairosubsets=lapply(pairs[p,],function(r) s[subsets[r,]]),其中p是您想要的配对的行数。
将其扩展到P(s)^n的情况(其中P(s)是集合s的幂集)会像这样:
setsosets = as.matrix(do.call(expand.grid,replicate(n,1:nrow(subsets),simplify=FALSE)))

这里,每一行都有一个数字向量。每个数字对应于 subsets 矩阵中的一行。


复制 s 元素可能对你之后的操作并不必要。但是,你可以在这里使用 lapply(1:nrow(pairs),function(p)lapply(pairs[p,],function(r) s[subsets[r,]])) 进行复制,它的第一部分类似于...

[[1]]
[[1]]$Row1
integer(0)

[[1]]$Row2
integer(0)


[[2]]
[[2]]$Row1
[1] 1

[[2]]$Row2
integer(0)

1
allSubsets<-function(n,# size of initial set
                     m,# number of subsets
                    includeEmpty=FALSE)# should the empty set be consiered a subset?

{

    # m can't exceed the number of possible subsets
    if(includeEmpty)
        stopifnot(m <= 2^n)
    else
        stopifnot(m <= 2^n-1)

    # get the subsets of the initial set (of size n)
    if(includeEmpty){
        ll <- split(t(combn(2^n,m)),seq(choose(2^n,m)))
    }else
        ll <- split(t(combn(2^n-1,m)),seq(choose(2^n-1,m)))

    # get the subets 
    subsets <- apply(do.call(expand.grid,rep(list(c(F,T)),n)),
                     1,which)
    # remove the empty subset if desired
    if(!includeEmpty)
        subsets <- subsets[-1]

    # covert the subsets to vector
    subsets <- lapply(subsets,as.vector)

    # return the list of subsets
    apply(t(mapply('[',list(subsets),ll)),1,function(x)x)

}

# returns a list where each element is a list of length 2 with 
# subsets of the initial set of length 4
x = allSubsets(4,2,F)

原来我的“子集”函数只是一种花哨版的“组合”函数。一个完整的示例已经替换了旧帖子结尾处的建议。 - Jthorpe

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