重复的组合

时间:2010-11-30 22:12:10

标签: wolfram-mathematica combinations repeat

我正在使用Mathematica 7并使用combinatorica包函数我可以从一个元素列表中得到一定数量的所有组合,其中顺序无关紧要且没有重复.g:

in: KSubsets[{a, b, c, d}, 3]
out: {{a, b, c}, {a, b, d}, {a, c, d}, {b, c, d}}

我找不到一个函数,它会从订单无关紧要且 重复的元素列表中给出一定数量的所有组合。 即,上述示例将在输出中包含{a,a,b},{a,a,a},{b,b,b}等元素。

可能需要自定义功能。如果我能想出一个,我会发一个答案但是现在我没有看到明显的解决方案。

编辑: 理想情况下,输出不包含组合的重复,例如  元组[{a,b,c,d},3] 将返回一个包含两个元素的列表,如{a,a,b}和{b,a,a} 从组合的角度来看是相同的。

4 个答案:

答案 0 :(得分:10)

您可以将每个组合编码为{na,nb,nc,nd},其中na表示a出现的次数。然后,任务是找到加起来为3的4个非负整数的所有可能组合。IntegerPartition提供了一种快速生成所有此类组合的方法,其中顺序无关紧要,并且您使用{{Permutations跟随它1}}以解释不同的订单

vars = {a, b, c, d};
len = 3;
coef2vars[lst_] := 
 Join @@ (MapIndexed[Table[vars[[#2[[1]]]], {#1}] &, lst])
coefs = Permutations /@ 
   IntegerPartitions[len, {Length[vars]}, Range[0, len]];
coef2vars /@ Flatten[coefs, 1]

只是为了好玩,这里有针对此任务的IntegerPartitions和Tuples之间的时序比较,以log-seconds为单位

approach1[numTypes_, len_] := 
  Union[Sort /@ Tuples[Range[numTypes], len]];
approach2[numTypes_, len_] := 
  Flatten[Permutations /@ 
    IntegerPartitions[len, {numTypes}, Range[0, len]], 1];

plot1 = ListLinePlot[(AbsoluteTiming[approach1[3, #];] // First // 
       Log) & /@ Range[13], PlotStyle -> Red];
plot2 = ListLinePlot[(AbsoluteTiming[approach2[3, #];] // First // 
       Log) & /@ Range[13]];
Show[plot1, plot2]

http://yaroslavvb.com/upload/save/tuples-vs-partitions.png

答案 1 :(得分:7)

DeleteDuplicates[Map[Sort, Tuples[{a, b, c, d}, 3]]]

答案 2 :(得分:2)

High Performance Mark给出的优雅方法略有不同:

Select[Tuples[{a, b, c, d}, 3], OrderedQ]

排列稍微多样化(但不是你想要的?)

例如:

Select[Permutations[
  Sort@Flatten@ConstantArray[{a, b, c, d}, {3}], {2, 3}], OrderedQ]

给出以下

alt text

编辑:

Select[Tuples[Sort@{a, b, d, c}, 3], OrderedQ]

可能更好

编辑-2

当然,也可以使用案例。例如

Cases[Permutations[
  Sort@Flatten@ConstantArray[{a, b, d, c}, {3}], {2, 3}], _?OrderedQ]

编辑-3。

如果列表包含重复元素,则这两种方法会有所不同。输出来自 例如,以下(方法2)将包含重复项(可能需要也可能不需要):

Select[Tuples[{a, b, c, d, a}, 3], OrderedQ]

他们可能很容易摆脱:

Union@Select[Tuples[{a, b, c, d, a}, 3], OrderedQ]

以下评估为'True'(从显示到方法2的列表中删除重复元素,并对方法1生成的列表进行排序(高性能标记方法):

lst = RandomInteger[9, 50]; 
Select[Union@Sort@Tuples[lst, 3], OrderedQ] == 
 Sort@DeleteDuplicates[Map[Sort, Tuples[lst, 3]]]

如下所示(从方法2的输出中删除重复项,方法1的排序输出):

lst = RandomInteger[9, 50]; 
Union@Select[Sort@Tuples[lst, 3], OrderedQ] == 
 Sort@DeleteDuplicates[Map[Sort, Tuples[lst, 3]]]

对不起!

答案 3 :(得分:2)

这是一个简单的解决方案,它利用了Mathetmatica的内置函数子集,因此在简单性和性能之间取得了很好的平衡。在[n + k-1]的k子集和[n]的k-组合之间存在简单的双射与重复。此功能可将子集更改为重复组合。

CombWithRep[n_, k_] := #-(Range[k]-1)&/@Subsets[Range[n+k-1],{k}]

所以

CombWithRep[4,2]

产量

{{1,1},{1,2},{1,3},{1,4},{2,2},{2,3},{2,4},{3,3},{3,4},{4,4}}