2014-02-20 76 views
1

我想了很多,並且找不到答案:如何在未知數量的數組中獲取未知數量的元素的所有組合?

我需要編寫一個js函數來獲取具有未知數量的數組的對象,該數組又有一個未知數元素的數量。像這樣:

{ 
    Color: ["Color : Red", "Color : Blue", "Color : Green"], 
    Size : ["Size : S", "Size : M", "Size : L"], 
    Material : ["Material : Cotton"], 
    Something : ["Something : Anything", "Something : Anotherthing"] 
} 

同樣,這可能是很多更多(或更少)的陣列和元素,但在這種情況下,我想實現這樣的輸出:

{0: "Color : Red > Size : S > Material : Cotton > Something : Anything", 
1: "Color : Red > Size : S > Material : Cotton > Something : Anotherthing", 
2: "Color : Red > Size : M > Material : Cotton > Something : Anything", 
3: "Color : Red > Size : M > Material : Cotton > Something : Anotherthing", 
4: "Color : Red > Size : L > Material : Cotton > Something : Anything", 
5: "Color : Red > Size : L > Material : Cotton > Something : Anotherthing", 
6: "Color : Blue > Size : S > Material : Cotton > Something : Anything", 
... 
...[and so forth... ]} 

我試着在循環中做循環,但失敗了。 然後我第一次嘗試尋找最長陣列,從休息中提取,然後通過每一個陣列中最長的每一個元素循環:

createMap = function(tagObj, longest){ 

    var longObj = tagObj[longest]; 
    var current = {}; 

    delete tagObj[longest]; 

    $.each(tagObj, function(name, obj){ 
    $.each(obj, function(index, tag){ 
     $.each(longObj, function(i, iniTag){ 
     if (current[i]!= undefined){ 
      current[i] += " > " + tag; 
     } 
     else current[i] = iniTag + " > " + tag; 
     }) 
    }) 
    }) 
    console.log(current); 
} 

但這只是導致:

{0: "Color : Red, Size : S, Size : M, Size : L, .... "} 

希望我不僅僅忽略了一些非常明顯的事情 - 但是我花了太多時間在這件事上,只是無法弄清楚。現在我是一個緊張的沉船,不能再直接思考了。 我非常感謝一些幫助!提前致謝!

+0

你不應該在這裏嵌套比2更深的東西。遍歷對象鍵和每個鍵,遍歷它的值(這是一個數組)。 –

+1

您將要遇到的問題是主對象中的鍵沒有保證的遍歷順序。這意味着你無法預測組合字符串的外觀。 「顏色」屬性*可能是第一個,或者它可能不是第一個。 – Pointy

+0

那麼,最初的順序並不重要,但是你是對的,最後,輸出應該都具有相同的順序。我甚至沒有到達那裏。 Thx @Pointy指出它! – stuckoverflow

回答

0

你可以用一些多種計數器來完成它:首先收集每個鍵和它的元素數量,以及每個鍵的計數器。

作爲一個數字基礎(但基數根據數字變化),我們增加下面的數字,如果這個數字達到允許的最大數量,我們把它放回0並遞增下一個數字。數字已經增加了,我們通過元素完成了一個完整的循環。

function combinations(obj) 
{ 
    var output = []; 
    var meta = [], ml, cm; 
    //ml: meta length 
    //cm: current meta (in the while loop) 

    for(var p in obj) if(obj.hasOwnProperty(p)) 
    { 
     if(Object.prototype.toString.call(obj[p]) != '[object Array]') 
      obj[p] = [obj[p]]; 
     meta.push({prop: p, len: obj[p].length, current: 0}); 
    } 
    function addNow() 
    { 
     var add = {}; 
     for(var i = 0, l = meta.length; i < l; i++) 
      add[meta[i].prop] = obj[meta[i].prop][meta[i].current] 
     output.push(add); 
    } 
    cm = ml = meta.length - 1; 
    while(cm >= 0) 
    { 
     addNow(); 
     cm = ml; 
     while(cm >= 0 && ++meta[cm].current >= meta[cm].len) 
     { 
      meta[cm].current = 0; 
      cm--; 
     } 
    } 
    return output; 
} 

(見this fiddle

0

你可以使用這個簡單的遞歸解決方案:

function combine(obj) { 
    var keys = Object.keys(obj), combinations = []; 

    // keys.sort(); // optional 

    function rc(ki, combo) { 
    var list; 

    if (ki === keys.length) 
     combinations.push(combo); 
    else { 
     list = obj[ keys[ki] ]; 
     for (var i = 0; i < list.length; ++i) 
     rc(ki + 1, combo + " " + list[i]); 
    } 
    } 

    rc(0, ''); 
    return combinations; 
} 

與起始對象的密鑰列表開始,和一個空的結果數組。請注意,對鍵進行排序可能是明智的做法,以便以可預測的順序返回結果,因爲對屬性名稱列表沒有定義的順序。

遞歸「rc」函數以鍵的數組中的特定索引開始。對於與該鍵相關聯的數組中的每個字符串,該函數將遞歸調用以對下一個鍵進行操作,並且通過將list元素附加到傳入的字符串的末尾來形成基本字符串。用完後,每個完成的組合字符串被追加到結果列表中。

通過爲第零個鍵調用「rc」並將空字符串作爲起始值來調用該過程。

相關問題