【问题标题】:Combinations with repetition与重复的组合
【发布时间】:2010-11-30 22:12:09
【问题描述】:

我正在使用 Mathematica 7 和组合包函数,我可以从元素列表中获取特定数字的所有组合,其中顺序无关紧要并且没有重复。例如:

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} 从组合的角度来看是相同的。

【问题讨论】:

    标签: wolfram-mathematica combinations repeat


    【解决方案1】:

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

    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]
    


    (来源:yaroslavvb.com

    【讨论】:

    • 可能看起来太复杂了?
    【解决方案2】:
    DeleteDuplicates[Map[Sort, Tuples[{a, b, c, d}, 3]]]
    

    【讨论】:

    • 请注意,Sort[#]&Sort 相同。
    • @TomD -- 确实如此,我的第一个版本使用了 Union,然后我在文档中发现了 DeleteDuplicates,它的名称更能说明它在这种情况下的作用。
    【解决方案3】:

    这是一个简单的解决方案,它利用了 Mathematica 的内置函数 Subsets,因此在简单性和性能之间取得了很好的平衡。在 [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}}
    

    【讨论】:

      【解决方案4】:

      High Performance Mark 给出的优雅方法的轻微变体:

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

      排列更加通用(但不是您想要的?)

      例如:

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

      给出以下内容

      编辑:

      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]
      

      以下评估为“真”(从提供给方法 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]]]
      

      对不起!

      【讨论】:

      • 如果你执行 Select[#,OrderedQ],你可以取消排序
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-17
      • 2015-01-02
      • 1970-01-01
      • 2013-08-22
      相关资源
      最近更新 更多