7

我需要根据 N 个属性列表生成一整套变体,同时保持属性名称不变。

var input = [
    { 'colour' : ['red', 'green'] },
    { 'material' : ['cotton', 'wool', 'silk'] },
    { 'shape' : ['round', 'square', 'rectangle'] }
];

var expected = [
    { 'colour': 'red', 'material': 'cotton', 'shape': 'round' },
    { 'colour': 'red', 'material': 'cotton', 'shape': 'square' },
    { 'colour': 'red', 'material': 'cotton', 'shape': 'rectangle' },
    { 'colour': 'red', 'material': 'wool', 'shape': 'round' },
    { 'colour': 'red', 'material': 'wool', 'shape': 'square' },
    { 'colour': 'red', 'material': 'wool', 'shape': 'rectangle' },
    { 'colour': 'red', 'material': 'silk', 'shape': 'round' },
    { 'colour': 'red', 'material': 'silk', 'shape': 'square' },
    { 'colour': 'red', 'material': 'silk', 'shape': 'rectangle' },
    { 'colour': 'green', 'material': 'cotton', 'shape': 'round' },
    { 'colour': 'green', 'material': 'cotton', 'shape': 'square' },
    { 'colour': 'green', 'material': 'cotton', 'shape': 'rectangle' },
    { 'colour': 'green', 'material': 'wool', 'shape': 'round' },
    { 'colour': 'green', 'material': 'wool', 'shape': 'square' },
    { 'colour': 'green', 'material': 'wool', 'shape': 'rectangle' },
    { 'colour': 'green', 'material': 'silk', 'shape': 'round' },
    { 'colour': 'green', 'material': 'silk', 'shape': 'square' },
    { 'colour': 'green', 'material': 'silk', 'shape': 'rectangle' }
];

对于数组的笛卡尔积,有很多算法,但我似乎找不到一种用于保留键的对象。

性能并不是一个大问题,因为每个属性的值永远不会超过十几个。顺序不必完全匹配expected

我已经根据列表的标准算法进行了初步尝试,但我很挣扎:

function cartesianProduct(input, current) {
    if (!input || input.length < 1) {
        return [];
    }

    var head = input[0];
    var tail = input.slice(1);
    var output = [];

    for (var key in head) {
        for (var i = 0; i < head[key].length; i++) {
            if (typeof current == 'undefined') {
                var current = {};
            }

            current[key] = head[key][i];
            var productOfTail = cartesianProduct(tail, current);
            output.push(current);
            console.log(current);
        }
    }

    return output;
}

console.log(cartesianProduct(input));
4

2 回答 2

7

一旦你摆脱了''i' is a global var issue',你可以使用下面的代码得到结果:

var input = [
    { 'colour' : ['red', 'green'] },
    { 'material' : ['cotton', 'wool', 'silk'] },
    { 'shape' : ['round', 'square', 'rectangle'] }
];

function cartesianProduct(input, current) {
   if (!input || !input.length) { return []; }

   var head = input[0];
   var tail = input.slice(1);
   var output = [];

    for (var key in head) {
      for (var i = 0; i < head[key].length; i++) {
            var newCurrent = copy(current);         
            newCurrent[key] = head[key][i];
            if (tail.length) {
                 var productOfTail = 
                         cartesianProduct(tail, newCurrent);
                 output = output.concat(productOfTail);
            } else output.push(newCurrent);
       }
     }    
    return output;
}

function copy(obj) {
  var res = {};
  for (var p in obj) res[p] = obj[p];
  return res;
}


console.log(cartesianProduct(input));
于 2013-09-23T12:48:28.460 回答
2

这是使用 Ramda.js 的解决方案

const input = [
  {
    'colour': ['red', 'green']
  },
  {
    'material': ['cotton', 'wool', 'silk']
  },
  {
    'shape': ['round', 'square', 'rectangle']
  }
]

const cartesianProductList = (Xs) => (
  R.reduce(
    (Ys, X) => (
      R.map(R.apply(R.append), R.xprod(X, Ys))
    ), 
    [[]],
    Xs
  )
)

const xPairs = (x, xs) => (
  R.map(R.pair(x), xs)
)

const cartesianProductObject = (objs) => (
  R.pipe(
    R.mergeAll,
    R.toPairs,
    R.map(R.apply(xPairs)),
    cartesianProductList,
    R.map(R.fromPairs),
  )(objs)
)

console.log(cartesianProductObject(input))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

于 2019-06-06T03:31:53.100 回答