2009-04-17 111 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