2010-10-30 54 views
6

的每個組合我有以陣列幾個號碼輸出的數字陣列與JavaScript

var numArr = [1, 3, 5, 9]; 

欲循環通過該數組和乘每個唯一的3號組合如下:

1 * 3 * 5 = 
1 * 3 * 9 = 
1 * 5 * 9 = 
3 * 5 * 9 = 

然後返回所有的計算陣列

var ansArr = [15,27,45,135]; 

任何人都有一個優雅的解決方案?提前致謝。

+3

在你要求排列的標題中,但在你提到的組合體中。這是什麼? (我猜組合,因爲乘法是可交換的。) – 2010-10-30 23:20:02

+1

@DaveKingsnorth注意:你的數組中有字符串,而不是數字。 – 2010-10-30 23:25:29

+0

對不起,這是組合 – DaveKingsnorth 2010-10-30 23:25:37

回答

11

通用算法如下:

function combinations(numArr, choose, callback) { 
    var n = numArr.length; 
    var c = []; 
    var inner = function(start, choose_) { 
     if (choose_ == 0) { 
      callback(c); 
     } else { 
      for (var i = start; i <= n - choose_; ++i) { 
       c.push(numArr[i]); 
       inner(i + 1, choose_ - 1); 
       c.pop(); 
      } 
     } 
    } 
    inner(0, choose); 
} 

在你的情況,你可以把它像這樣:

function product(arr) { 
    p = 1; 
    for (var i in arr) { 
     p *= arr[i]; 
    } 
    return p; 
} 

var ansArr = []; 

combinations(
    [1, 3, 5, 7, 9, 11], 3, 
    function output(arr) { 
     ansArr.push(product(arr)); 
    }); 

document.write(ansArr); 

...其中,用於給定的輸入,產生此:

15,21,27,33,35,45,55,63,77,99,105,135,165,189,231,297,315,385,495,693 
+0

這太棒了。非常感謝! – DaveKingsnorth 2010-10-31 00:13:38

2

我認爲這應該工作:

var a = [1, 3, 5, 9]; 
var l = a.length; 
var r = []; 
for (var i = 0; i < l; ++i) { 
    for (var j = i + 1; j < l; ++j) { 
    for (var k = j + 1; k < l; ++k) { 
     r.push(a[i] * a[j] * a[k]); 
    } 
    } 
} 

編輯

只是我自己的薰陶,我想通了,使用的,而不是遞歸循環一個通用的解決方案。顯而易見的缺點是,加載或閱讀時間較長。另一方面(至少在我的機器上是Firefox),它的運行速度是遞歸版本的兩倍。但是,如果您正在爲大集合找到組合,或者在同一頁面上多次查找組合,我只會推薦它。無論如何,如果有人有興趣,這是我想出的。

產生組合
function combos(superset, size) { 
    var result = []; 
    if (superset.length < size) {return result;} 
    var done = false; 
    var current_combo, distance_back, new_last_index; 
    var indexes = []; 
    var indexes_last = size - 1; 
    var superset_last = superset.length - 1; 

    // initialize indexes to start with leftmost combo 
    for (var i = 0; i < size; ++i) { 
    indexes[i] = i; 
    } 

    while (!done) { 
    current_combo = []; 
    for (i = 0; i < size; ++i) { 
     current_combo.push(superset[indexes[i]]); 
    } 
    result.push(current_combo); 
    if (indexes[indexes_last] == superset_last) { 
     done = true; 
     for (i = indexes_last - 1; i > -1 ; --i) { 
     distance_back = indexes_last - i; 
     new_last_index = indexes[indexes_last - distance_back] + distance_back + 1; 
     if (new_last_index <= superset_last) { 
      indexes[indexes_last] = new_last_index; 
      done = false; 
      break; 
     } 
     } 
     if (!done) { 
     ++indexes[indexes_last - distance_back]; 
     --distance_back; 
     for (; distance_back; --distance_back) { 
      indexes[indexes_last - distance_back] = indexes[indexes_last - distance_back - 1] + 1; 
     } 
     } 
    } 
    else {++indexes[indexes_last]} 
    } 
    return result; 
} 

function products(sets) { 
    var result = []; 
    var len = sets.length; 
    var product; 
    for (var i = 0; i < len; ++i) { 
    product = 1; 
    inner_len = sets[i].length; 
    for (var j = 0; j < inner_len; ++j) { 
     product *= sets[i][j]; 
    } 
    result.push(product); 
    } 
    return result; 
} 

console.log(products(combos([1, 3, 5, 7, 9, 11], 3))); 
+0

完美!非常感謝 – DaveKingsnorth 2010-10-30 23:51:04

+0

如果我想得到所有2個數字組合或5個數字組合(如果我有一個更長的數組),是否有解決方案,我可以指定該值作爲變量(我正在談論指定的長度組合)。 – DaveKingsnorth 2010-10-30 23:59:27

+0

@DaveKingsnorth如果你想改變這一點,那麼我的解決方案太具體。參見Marcelo更通用的解決方案。 – 2010-10-31 00:12:31

0

當您需要在n個數字中選擇k個數字時,執行此操作的遞歸函數。沒有測試過。如果發現有任何錯誤,並糾正它:-)

var result = []; 

foo(arr, 0, 1, k, n); // initial call 

function foo(arr, s, mul, k, n) { 
    if (k == 1) { 
     result.push(mul); 
     return; 
    } 

    var i; 
    for (i=s; i<=n-k; i++) { 
     foo(arr, i+1, mul*arr[i], k-1, n-i-1); 
    } 
} 

這是一個遞歸函數。

  1. 第一個參數是數組arr。第二個參數是整數s。每次調用都會從索引s開始計算數組的一部分值。遞歸地增加s,因此每個調用的數組遞歸地變小。

  2. 第三個參數是遞歸計算並在遞歸調用中傳遞的值。當k變爲1時,它被添加到結果數組中。

  3. k中所需的組合的尺寸。它遞歸遞減,當成爲1時,輸出附加在結果數組中。

  4. n是數組大小arr。其實n = arr.length

+0

@ Niraj - 你能解釋一下每一個參數嗎? – DaveKingsnorth 2010-10-31 00:57:49

+0

這是一個遞歸函數。 1)第一個參數是數組arr。 2)第二個參數是整數s。每次調用都會從索引s開始計算數組的一部分值。遞歸地增加s,所以每個調用的數組遞歸地變小。 3)第三個參數是遞歸計算並在遞歸調用中傳遞的值。當k變爲1時,它被添加到結果數組中。 4)k在所需的組合的大小。它遞歸遞減,當成爲1時,輸出附加在結果數組中。 5)n是數組arr的大小。其實n = arr.length – 2010-10-31 07:31:37

+0

這就是我的想法,但我仍然在某個地方犯錯。我打這樣的函數: var arr = [2,1,4,1,6]; foo(arr,0,1,4,5); 並輸出它像這樣:document.write(result);我究竟做錯了什麼? – DaveKingsnorth 2010-11-02 00:23:26

-1

使用節點,你可以很容易地使用庫來做到這一點。

npm install bit-twiddle 

然後你可以使用它在你的代碼是這樣的::

//Assume n is the size of the set and k is the size of the combination 
var nextCombination = require("bit-twiddle").nextCombination 
for(var x=(1<<(k+1))-1; x<1<<n; x=nextCombination(x)) { 
    console.log(x.toString(2)) 
} 

變量x是一個位向量,其中位i設置如果i個元素是第一次使用NPM安裝bit-twiddle包含在組合中。

0
var create3Combi = function(array) { 
    var result = []; 
    array.map(function(item1, index1) { 
     array.map(function(item2, index2) { 
      for (var i = index2 + 1; i < array.length; i++) { 
       var item3 = array[i]; 
       if (item1 === item2 || item1 === item3 || item2 === item3 || index2 < index1) { 
        continue; 
       } 
       result.push([item1, item2, item3]); 
      } 
     }); 
    }); 

    return result; 
}; 

var multiplyCombi = function(array) { 
    var multiply = function(a, b){ 
     return a * b; 
    }; 

    var result = array.map(function(item, index) { 
     return item.reduce(multiply); 
    }); 

    return result; 
} 

var numArr = [1, 3, 5, 9]; 

// create unique 3 number combination 
var combi = create3Combi(numArr); //[[1,3,5],[1,3,9],[1,5,9],[3,5,9]] 

// multiply every combination 
var multiplyResult = multiplyCombi(combi); //[15,27,45,135];