2016-08-01 59 views
0

我必須製作一個具有屬性值的所有組合的數組。如何從屬性值生成變化

屬性/值對象:

let attributes = { 
    color: ['red', 'green', 'blue'], 
    sizes: ['sm', 'md', 'lg'], 
    material: ['cotton', 'wool'] 
} 

我需要使所有可能的組合作爲這樣的陣列。

color sizes  material 
red  sm  cotton 
red  sm  wool 
red  md  cotton 
red  md  wool 
red  lg  cotton 
red  lg  wool 
blue  sm  cotton 
blue  sm  wool 
blue  md  cotton 
blue  md  wool 
blue  lg  cotton 
blue  lg  wool 
green sm  cotton 
green sm  wool 
green md  cotton 
green md  wool 
green lg  cotton 
green lg  wool 

屬性類型和值計數都是不確定的(至少爲1)。我怎樣才能做到這一點?

這是我迄今爲止

// keys = ['color', 'sizes', 'material'] 
// attributes is the same as above. 

for (let keysIndex = 0; keysIndex < keys.length; keysIndex++) { 
    let key = keys[i]; 
    let values = attributes[key]; 

    //loop through each value 
    for (let valuesIndex = 0; valuesIndex < values.length; valuesIndex++) { 

     // for each value, loop through all keys 
     for (let keysIndex2 = 0; keysIndex2 < keys.length; keysIndex2++) { 
      if (keysIndex === keysIndex2) { 
       continue; 
      } 

      for (let valuesIndex2 = 0; valuesIndex2 < values.length; valuesIndex2++) { 

       // What do I do from here? 
       // Not sure if this is even the right path? 

      } 

     } 

    } 

} 
+0

您感興趣的任何特定語言? – smarx

+0

Javascript會很好,但我只是在尋找算法。 – Jeff

+1

它被稱爲*笛卡爾產品*(並且有很多JS解決方案,例如[this one])(http://stackoverflow.com/a/15310051/1048572)) – Bergi

回答

1

我採取了兩個步驟的方法的代碼...第一I從attributes對象提取只是數組的數組([['red', 'green', 'blue'], ['sm', ...], ...])。然後我遞歸地計算這些數組的產品。然後,我用適當的鍵將它們放回物體中。

let attributes = { 
    color: ['red', 'green', 'blue'], 
    sizes: ['sm', 'md', 'lg'], 
    material: ['cotton', 'wool'] 
}; 

let getProducts = (arrays) => { 
    if (arrays.length === 0) { 
     return [[]]; 
    } 

    let results = []; 

    getProducts(arrays.slice(1)).forEach((product) => { 
     arrays[0].forEach((value) => { 
      results.push([value].concat(product)); 
     }); 
    }); 

    return results; 
}; 

let getAllCombinations = (attributes) => { 
    let attributeNames = Object.keys(attributes); 

    let attributeValues = attributeNames.map((name) => attributes[name]); 

    return getProducts(attributeValues).map((product) => { 
     obj = {}; 
     attributeNames.forEach((name, i) => { 
      obj[name] = product[i]; 
     }); 
     return obj; 
    }); 
}; 

console.log(getAllCombinations(attributes)); 

// Output: 
// [ { color: 'red', sizes: 'sm', material: 'cotton' }, 
// { color: 'green', sizes: 'sm', material: 'cotton' }, 
// { color: 'blue', sizes: 'sm', material: 'cotton' }, 
// { color: 'red', sizes: 'md', material: 'cotton' }, 
// { color: 'green', sizes: 'md', material: 'cotton' }, 
// { color: 'blue', sizes: 'md', material: 'cotton' }, 
// { color: 'red', sizes: 'lg', material: 'cotton' }, 
// { color: 'green', sizes: 'lg', material: 'cotton' }, 
// { color: 'blue', sizes: 'lg', material: 'cotton' }, 
// { color: 'red', sizes: 'sm', material: 'wool' }, 
// { color: 'green', sizes: 'sm', material: 'wool' }, 
// { color: 'blue', sizes: 'sm', material: 'wool' }, 
// { color: 'red', sizes: 'md', material: 'wool' }, 
// { color: 'green', sizes: 'md', material: 'wool' }, 
// { color: 'blue', sizes: 'md', material: 'wool' }, 
// { color: 'red', sizes: 'lg', material: 'wool' }, 
// { color: 'green', sizes: 'lg', material: 'wool' }, 
// { color: 'blue', sizes: 'lg', material: 'wool' } ] 
+0

完美的作品。感謝您的幫助。關於如何更好地解決問題的任何提示?我從來都不擅長算法。 – Jeff

+1

我認爲這樣的關鍵是要認識到遞歸將是解決它的最自然的方法。你可以爲你所擁有的三個屬性寫三個for循環,但如果你事先不知道會有多少屬性,那麼這是行不通的。將問題分解爲「讓我們先選擇一種顏色,然後選擇其餘的」,使算法變得更簡單。 (爲第一個屬性選擇值;遞歸調用以獲取其餘屬性。)最後,您只需決定基本情況。 (當沒有其他「屬性的其餘部分」時,請返回。) – smarx