2016-08-01 56 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