如何在JavaScript中创建此对象的键/值的所有组合?

时间:2015-09-29 07:41:33

标签: javascript algorithm recursion combinations permutation

我有以下JavaScript对象结构:

var options = {
    optionOne: [true, false],
    optionTwo: [true, false],
    optionThree: [
        null,
        {property1: 9, property2: 7},
        {property1: 4, property2: 12},
        {property1: 16, property2: 14}
    ]
};

请注意,此对象中的键/对数量会有所不同。因此实际上可能有optionFouroptionFive等,并且每个选项可以为其数组提供任意数量或类型的值。

我需要遍历此对象并创建一个包含所有可能选项组合的对象的数组:

[
    {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}}
]

我正在努力想要如何实现这一点,但我相当自信答案在于递归。

算法神可以帮助我吗?

3 个答案:

答案 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']
]

然后combinationsObject.keysObject.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);
  • 细微的语义改进