我有以下JavaScript对象结构:
var options = {
optionOne: [true, false],
optionTwo: [true, false],
optionThree: [
null,
{property1: 9, property2: 7},
{property1: 4, property2: 12},
{property1: 16, property2: 14}
]
};
请注意,此对象中的键/对数量会有所不同。因此实际上可能有optionFour
,optionFive
等,并且每个选项可以为其数组提供任意数量或类型的值。
我需要遍历此对象并创建一个包含所有可能选项组合的对象的数组:
[
{optionOne: true, optionTwo, true, optionThree: null},
{optionOne: false, optionTwo, true, optionThree: null},
{optionOne: true, optionTwo, false, optionThree: null},
{optionOne: false, optionTwo, false, optionThree: null},
{optionOne: true, optionTwo, true, optionThree: {property1: 9, property2: 7}},
{optionOne: false, optionTwo, true, optionThree: {property1: 9, property2: 7}},
{optionOne: true, optionTwo, false, optionThree: {property1: 9, property2: 7}},
{optionOne: false, optionTwo, false, optionThree: {property1: 9, property2: 7}},
{optionOne: true, optionTwo, true, optionThree: {property1: 4, property2: 12}},
{optionOne: false, optionTwo, true, optionThree: {property1: 4, property2: 12}},
{optionOne: true, optionTwo, false, optionThree: {property1: 4, property2: 12}},
{optionOne: false, optionTwo, false, optionThree: {property1: 4, property2: 12}},
{optionOne: true, optionTwo, true, optionThree: {property1: 16, property2: 14}},
{optionOne: false, optionTwo, true, optionThree: {property1: 16, property2: 14}},
{optionOne: true, optionTwo, false, optionThree: {property1: 16, property2: 14}},
{optionOne: false, optionTwo, false, optionThree: {property1: 16, property2: 14}}
]
我正在努力想要如何实现这一点,但我相当自信答案在于递归。
算法神可以帮助我吗?
答案 0 :(得分:10)
function getCombinations(options, optionIndex, results, current) {
var allKeys = Object.keys(options);
var optionKey = allKeys[optionIndex];
var vals = options[optionKey];
for (var i = 0; i < vals.length; i++) {
current[optionKey] = vals[i];
if (optionIndex + 1 < allKeys.length) {
getCombinations(options, optionIndex + 1, results, current);
} else {
// The easiest way to clone an object.
var res = JSON.parse(JSON.stringify(current));
results.push(res);
}
}
return results;
}
像这样使用:
var results = getCombinations(options, 0, [], {});
这是一个有效的JSFiddle example。
答案 1 :(得分:1)
这是最近复活的,我认为现代 JS 提供了一种更简洁的编写方式。
const crossproduct = (xss) =>
xss.reduce((xs, ys) => xs.flatMap(x => ys.map(y => [...x, y])), [[]])
const combinations = (o, keys = Object .keys (o), vals = Object .values (o)) =>
crossproduct(vals).map(xs => Object.fromEntries(xs.map ((x, i) => [keys[i], x])))
const options = {optionOne: [true, false], optionTwo: [true, false], optionThree: [null, {property1: 9, property2: 7}, {property1: 4, property2: 12}, {property1: 16, property2: 14}]}
console .log (JSON .stringify (
combinations (options)
, null, 4))
.as-console-wrapper {max-height: 100% !important; top: 0}
我们从一个 crossproduct
函数开始,例如,它需要
[[1, 2], ['a', 'b', 'c'], ['T', 'F']]
然后返回
[
[1, 'a', 'T'], [1, 'a', 'F'], [1, 'b', 'T'], [1, 'b', 'F'], [1, 'c', 'T'], [1, 'c', 'F'],
[2, 'a', 'T'], [2, 'a', 'F'], [2, 'b', 'T'], [2, 'b', 'F'], [2, 'c', 'T'], [2, 'c', 'F']
]
然后combinations
用Object.keys
和Object.values
将我们的对象分开,将值传递给crossproduct
,然后对于结果中的每个数组,映射值,将相应的键与每个键相关联,然后使用 Object.fromEntries
重新组合一个对象。
这个顺序对我来说似乎是结果的逻辑顺序。但是,如果我们将返回的 crossproduct
表达式替换为以下内容,我们将得到问题中提到的顺序:
xss .reduce ((xs, ys) => ys .flatMap (y => xs .map (x => [...x, y])), [[]])
答案 2 :(得分:0)
这是基于 Dmytro 的 answer 的改进:
function getPermutations(object, index = 0, current = {}, results = []) {
const keys = Object.keys(object);
const key = keys[index];
const values = object[key];
for (const value of values) {
current[key] = value;
const nextIndex = index + 1;
if (nextIndex < keys.length) {
this.getPermutations(object, nextIndex, current, results);
} else {
const result = Object.assign({}, current);
results.push(result);
}
}
return results;
}
改进:
const p = getPermutations(object);