2009-04-17 125 views
3

我有一个项目列表,每个项目都有一个数量。计算一系列的所有组合

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} 
.... 
+1

你的意思是“不是每个项目都必须存在于结果中?”你在找什么样的结果? – 2009-04-17 06:31:45

回答

1

只是做正常的组合。

对于具有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  
2

我假定每个项目的该数量是有限的。

我会去与增量位置: 空开始,虽然可能增加项目1。完成后,删除所有1并添加2并再次开始添加1。当达到容量时,将其全部移除,再添加2个,然后重新开始。当2S达产,将其删除,并添加3等等...

有点像数字工作。


好吧,让我们尝试编码...使用递增整数键的散列是一个数组;#) 假设数组的第一个元素是out'floating radix'数字的右边数字更容易。

这是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); 
    } 
}; 

添加一个div id为 '日志' 的文件,不知何故开始generateSets()方法检查出的输出。

+0

是的,我意识到一种方法是将每个组合视为混合基数,然后为了得到它们,您只需要从0到最大组合数。这现在导致我有一个不同的问题:http://stackoverflow.com/questions/759296/converting-a-decimal-to-a-mixed-radix-base-number – nickf 2009-04-17 06:58:54

2

更新:发布这个答案后,我注意到一个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])
  • ë TC

所以,你的问题可以被看作是简单的要求,可以通过表示的数字序列 - 而不是二进制 - 但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 

---- snip ---- 

2 
1,2 
1,1,2 

---- big snip ---- 

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