【问题标题】:Calculate all combinations of a series计算一个系列的所有组合
【发布时间】:2009-04-17 06:29:20
【问题描述】:

我有一个项目列表,每个项目都有一个数量。

var items = {
    1: 12,   // we have 12 x item1
    2: 1,    // we have 1 x item2
    3: 1,
    4: 7,
    5: 2,
    6: 2
};

或者,这可以被视为:

var items = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
             2, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 6, 6];

您将如何获取这些项目的每个组合的列表,请记住顺序完全不重要(因此[1,2,3] == [3,2,1]),并且并非每个项目都必须存在于结果中。

我想输出可能是这样的:

[1]
[1, 1]
[1, 2]
[1, 3]
...

或者,甚至更好:

{1 : 1}          // 1 x item1
{1 : 2}          // 2 x item1 
{1 : 1, 2 : 1}   // 1 x item1, 1 x item2
{1 : 1, 3 : 1}
....

【问题讨论】:

  • “不是每个项目都必须存在于结果中”是什么意思?您到底在寻找什么样的结果?

标签: javascript set combinations


【解决方案1】:

更新:发布此答案后,我注意到existing answer 具有相同的方法,但我仍然会保留我的方法,因为它更冗长,甚至还有工作代码:)


如果原始项目池中的每个项目只有一个实例,并且您的项目表示二进制数字;

var items {
    1 : 1,
    2 : 1,
    4 : 1,
    8 : 1,
    16: 1,
    32: 1
};

问题将被简化为生成可以由这些数字表示的所有数字的序列:

  • 0([ ] - 没有项目)
  • 1 ([ 1 ])
  • 2 ([ 2 ])
  • 3 ([ 2, 1 ])
  • 4 ([ 4 ])

因此,您的问题可以被视为简单地询问可以用 mixed-radix 数字系统表示的数字序列。

也就是说,您可以为这个奇怪的编号系统编写一个计数器来遍历值 0 和 MAX。因此,当您用尽所有可能的值时,您应该从增加最低有效位开始并结转到更高有效位。

var items = {
    1: 12,   // we have 12 x item1
    2: 1,    // we have 1 x item2
    3: 1,
    4: 7,
    5: 2,
    6: 2
};

var counter = {
    1: 0,
    2: 0,
    3: 0,
    4: 0,
    5: 0,
    6: 0
};

function increment(digit) {
    if (digit > 6) {
        return false;
    }

    var value = counter[digit] + 1;

    if (value > items[digit]) {
        counter[digit] = 0;
        return increment(digit + 1);
    }

    counter[digit] = value;

    return true;
}

while (increment(1)) {
    var set = [];

    for (var digit in counter) {
        var value = counter[digit];

        for (var i = 0; i < value; i++) {
            set.push(digit);
        }
    }

    document.write("<div>" + set + "</div>");
}

输出看起来像这样:

1 1,1 1,1,1 ---- 剪断 ---- 2 1,2 1,1,2 ---- 大剪 ---- 1,1,1,1,1,1,1,1,2,3,4,4,4,4,4,4,4,5,5,6,6 1,1,1,1,1,1,1,1,1,2,3,4,4,4,4,4,4,4,5,5,6,6 1,1,1,1,1,1,1,1,1,1,2,3,4,4,4,4,4,4,4,5,5,6,6 1,1,1,1,1,1,1,1,1,1,1,2,3,4,4,4,4,4,4,4,5,5,6,6 1,1,1,1,1,1,1,1,1,1,1,1,2,3,4,4,4,4,4,4,4,5,5,6,6

【讨论】:

    【解决方案2】:

    我假设每件商品的数量都是有限的。

    我会在这里使用增量: 从空开始并尽可能添加项目 1。完成后,删除所有 1 并添加 2 并再次开始添加。当一个达到容量时,将它们全部删除,再添加 2 个并重新开始。当 2s 达到容量时,将它们移除并添加 3。依此类推...

    有点像数字的工作。


    好的,让我们尝试编码...带有递增整数键的哈希是一个数组;-) 更容易假设数组的第一个元素是“浮动基数”数的正确数字。

    这是javaScript:

    var limits = [1, 3, 5, 2];
    
    function out(arr){
      var text = '';
      for (var i=0; i < arr.length; i++){
        text += arr[i] + '.'
      }
      var log = document.getElementById('log');
      var p = document.createElement('p');
      log.appendChild(p);
      p.innerHTML = '<span>' + text + '</span>';
    }
    
    function generateNextSet(set){
      for (var i = 0; i < set.length; i++){
        var amount = set[i];
        if (amount + 1 > limits[i]){
          set[i] = 0;
        } else {
          set[i] = amount + 1;
          return set;
        }
      }
      return false;
    }
    
    function generateSets(){
      var initial_set = [0, 0, 0, 0]
      var set = generateNextSet(initial_set);
      out(set);
      while (set = generateNextSet(set)) {
        out(set);
      }
    };
    

    在文档中添加一个 id 为 'log' 的 div,并以某种方式启动 generateSets() 方法来检查输出。

    【讨论】:

    【解决方案3】:

    只需进行正常的组合即可。

    对于每个有 n 个数量大于 1 的数字的基本集合,循环遍历所有数量:[5,6] -> [5,5,6], [5,6,6], [5,5 ,6,6]。

    []
    [1] -> [1,1], [1,1,1] etc
      [1,2] -> [1,1,2], ...
      [1,3] -> [1,1,3]
      [1,4] -> [1,1,4], ...., [1,4,4], -- all combinations of all multi quantity
    [2]
    [3]
    [4] -> [4,4], [4,4,4] etc
    [5] -> [5,5]
    [6] -> [6,6]
    

    等等……

    另一种方法(伪代码):

    Combinations: {N -> N} -> [[N]]
    Combinations(s) == CombinationsX(s, [])
    
    CombinationsX: {N -> N} X [N] -> [[N]]
    Combinationsx(s, g) ==
      if s = {} then return []
      else
        {a -> b} = hd s
        ts = tl s
        res = Combinationsx(ts, g) 
        for q in 1..b do
          g = g + [a]
          res = res ++ Combinationsx(ts, g)
        return res      
    

    【讨论】:

      【解决方案4】:

      combination generation 的一个很好的资源是 Kenneth H. Rosen 在Discrete Mathematics and Its Applications 中描述的算法。很多问题都可以利用这个通用算法,最好把它放在你的工具箱里。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-12-27
        • 1970-01-01
        • 2016-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-11
        相关资源
        最近更新 更多