从约束列表中生成所有可能的对象

时间:2017-05-15 04:16:37

标签: javascript algorithm

我正在尝试从约束哈希生成所有可能的对象。

让我们说约束是:

{
    key1: [ 'possible value1' , 'possible value2' ],
    key2: [ 2, 4, 7, 1],
    ...
}

我想生成所有可能的对象:

{ key1: 'possible value1', key2: 2 }

{ key1: 'possible value1', key2: 4 }

...

有人能指出我正确的方向吗?

谢谢!

3 个答案:

答案 0 :(得分:2)



var options = {
        key1: [ 'possible value1' , 'possible value2'],
        key2: [ 2, 4, 7, 1],
        key3: ['TEST1', 'TEST2']
};

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 {
            var res = JSON.parse(JSON.stringify(current));
            results.push(res);
        }
    }

    return results;
}

var results = getCombinations(options, 0, [], {});

document.body.innerHTML = JSON.stringify(results);
&#13;
&#13;
&#13;

答案 1 :(得分:1)

let constraints = {
  key1: ['possible value1' , 'possible value2'],
  key2: [2, 4, 7, 1],
  key3: ["foo", "bar"],
};

let result = Object.keys(constraints).reduce(
  (acc, key) =>
    acc.map(a1 =>
      constraints[key].map(a2 =>
        a1.concat([a2])
      )
    ).reduce((e1, e2) => e1.concat(e2)),
  [[]]
);

console.log(JSON.stringify(result));

首先,如果第一个包含数组(由一些约束集生成的所有数组)和第二个单个元素(一个新约束),我们首先确保知道如何对两个数组的所有元素进行连接。 (例如[["possible value1"], ["possible value2"][1, 2])。我们映射一个数组,映射另一个数组,然后将它们粘在一起(a1a2地图,a1.concat([a2]))。嵌套的map将生成一个两级数组,因此我们将只连接单个级别的所有数组(内部reduce)。

请注意,如果我们将空数组连接到数组,则数组不会更改;因此,我们可以引入另一个约束,一个空约束:[]。如果我们将与此约束对应的所有数组[[]]["possible value1", "possible value2"]组合在一起,我们仍会得到相同的集合。这是我们的外部reduce的起始值:从这个“null元素”开始,我们可以连接其他约束,如上所述。

编辑:做得更漂亮:

let constraints = {
  key1: ['possible value1' , 'possible value2'],
  key2: [2, 4, 7, 1],
  key3: ["foo", "bar"],
};

const unconstrainedPossibilities = [[]];

const flatten = array => array.reduce((a1, a2) => a1.concat(a2));

const addConstraint = (possibilities, constraint) =>
  flatten(
    possibilities.map(possibility =>
      constraint.map(constraintValue =>
        possibility.concat([constraintValue])
      )
    )
  );

const possibilitiesFor = constraints =>
  constraints.reduce(
    (possibilities, constraint) => addConstraint(possibilities, constraint),
    unconstrainedPossibilities
  );

let possibilities = possibilitiesFor(Object.values(constraints));
console.log(JSON.stringify(possibilities));

答案 2 :(得分:0)

我知道有更优雅的方法可以做到这一点,但我想提出一个并没有真正涉及太多思考的算法,所以,我的想法只是使用一个基本的while循环循环的每次迭代创建下一个组合并将其粘贴在输出数组中。

我首先创建一个keys数组,其中包含{k: "key1", index: 0, length: 2}形式中每个键的对象 - 基本上是为了跟踪该键,我们在其数组中使用哪个索引,它的数组有多长。然后while循环的第一行使用.reduce()使用每个键的当前索引的值构建一个对象,然后使用for循环移动到下一个组合。当它到达组合的末尾时,它会突破while循环。

&#13;
&#13;
const constraints = {
  key1: ['pv1', 'pv2', 'pv3', 'pv4'],
  key2: [2, 4, 7, 1],
  key3: ['a', 'b'],
  key4: [10, 20, 30]
}

const output = []

const keys = Object.keys(constraints)
  .map(k => ({ k: k, index: 0, length: constraints[k].length }))

process: while (true) {
  output.push(keys.reduce((a, c) => {
    a[c.k] = constraints[c.k][c.index];
    return a;
  }, {}))

  for (let i = keys.length - 1; i >= 0; i--) {
    keys[i].index++
    if (keys[i].index < keys[i].length) break
    if (i === 0) break process
    keys[i].index = 0
  }
}

console.log(JSON.stringify(output))
&#13;
&#13;
&#13;