2016-08-01 2 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, таких как [этот] (http://stackoverflow.com/a/15310051/1048572)) – Bergi

ответ

1

Я принял двухэтапный подход ... Я сначала извлекается из 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

Я думаю, что ключ к чему-то подобному заключается в том, чтобы признать, что рекурсия будет наиболее естественным способом ее решения. Вы * можете * написать три для циклов для трех атрибутов, которые у вас есть, но это не работает, если вы не знаете заранее, сколько атрибутов будет. Прервав проблему в «Сначала выберем цвет, а затем выберите все остальное», алгоритм намного проще. (Выберите значение для первого атрибута, вызовите рекурсивно, чтобы получить остальные атрибуты.) Наконец, вам просто нужно принять решение о базовом случае. (Когда больше нет «остальных атрибутов», просто вернитесь.) – smarx