-1

例如,我有一组数组

["a1", "a2"]
["b1", "b2", "b3"]
["c1", "c2"]
["d1", "d2", "d3", "d4"] 

可以有任意数量的这些数组。使用第一个数组,是否有一种好方法可以遍历记录每个组合的其他数组。

例如

a1,b1,c1,d1
a2,b1,c1,d1    
a1,b2,c1,d1
a2,b2,c1,d1
.
.
.
a1,b1,c1,d4
a2,b1,c1,d4
.
.
.
a1,b3,c2,d4
a2,b3,c2,d4

我正在尝试绘制概率树的结果,这部分让我陷入困境

4

2 回答 2

4

鉴于我理解你的问题是正确的,你在所有子阵列的笛卡尔积之后。

让我们从构建可能的最愚蠢的版本开始;没有聪明,只是一个双循环:

function product ( left, right ) {
    var ret = [];

    for (var i = 0; i < left.length; i++) {
        for (var j = 0; j < right.length; j++) {
            ret.push( [left[i], right[j]] );
        }
    }

    return ret;
}

我们简单地遵循产品的定义: 中的每个项目left与 中的每个项目right。让我们聪明一点:我们遍历两个数组,将每个左边的项映射到右边的项。也许如果我们使用Array#map...

function product ( left, right ) {
    return left.map(function ( i ) {
        return right.map(function ( j ) {
            return [i, j];
        });
    });
}

但是,这会创建一个嵌套数组:

> product( [0, 1], [2, 3] );
[ [[0,2], [0,3]],
  [[1,2], [1,3]] ]

我们可以通过减少第一个数组来解决这个问题:

function product ( left, right ) {
    return left.reduce(function ( ret, i ) {
        var ans = right.map(function ( j ) {
            return [i, j];
        });

        return ret.concat( ans );
    }, []);
}

到目前为止,这描述了产品left × right,但是您想要一个 n 元产品:A × B × C × ...我们将如何做到这一点?

我们将使用笛卡尔积的一个非常有用的特征:A × B × C = A × (B × C). 这意味着我们可以递归地定义一个 n 元乘积。这是第一次尝试:

function product ( left, right, other ) {
    if ( other ) {
        right = product.apply( this, [].slice.call(arguments, 1) );
    }

    return left.reduce(function ( ret, i ) {
        var ans = right.map(function ( j ) {
            return [i, j];
        });

        return ret.concat( ans );
    }, []);
}

错误应该很清楚:[i, j]. 这假设我们有两个标量(常规的、平坦的值),而实际上我们有一个标量和一个数组。修复很简单:我们不是将结果包装在数组中,而是将数组连接到标量,从而得到最终解决方案:

function product ( left, right, other ) {
    if ( other ) {
        right = product.apply( this, [].slice.call(arguments, 1) );
    }

    return left.reduce(function ( ret, i ) {
        var ans = right.map(function ( j ) {
            return [i].concat( j );
        });

        return ret.concat( ans );
    }, []);
}

在您的情况下,由于您有一个数组数组,因此在调用时,您需要将其展平:

> var arr = [ ["a1", "a2"], ["b1", "b2", "b3"], ["c1", "c2"], ["d1", "d2", "d3", "d4"] ];
undefined
> product.apply( null, arr );
[ [ 'a1', 'b1', 'c1', 'd1' ],
  [ 'a1', 'b1', 'c1', 'd2' ],
  [ 'a1', 'b1', 'c1', 'd3' ],
  [ 'a1', 'b1', 'c1', 'd4' ],
  [ 'a1', 'b1', 'c2', 'd1' ],
  [ 'a1', 'b1', 'c2', 'd2' ],
  [ 'a1', 'b1', 'c2', 'd3' ],
  [ 'a1', 'b1', 'c2', 'd4' ],
  [ 'a1', 'b2', 'c1', 'd1' ],
  [ 'a1', 'b2', 'c1', 'd2' ],
  [ 'a1', 'b2', 'c1', 'd3' ],
  [ 'a1', 'b2', 'c1', 'd4' ],
  [ 'a1', 'b2', 'c2', 'd1' ],
  [ 'a1', 'b2', 'c2', 'd2' ],
  [ 'a1', 'b2', 'c2', 'd3' ],
  [ 'a1', 'b2', 'c2', 'd4' ],
  [ 'a1', 'b3', 'c1', 'd1' ],
  [ 'a1', 'b3', 'c1', 'd2' ],
  [ 'a1', 'b3', 'c1', 'd3' ],
  [ 'a1', 'b3', 'c1', 'd4' ],
  [ 'a1', 'b3', 'c2', 'd1' ],
  [ 'a1', 'b3', 'c2', 'd2' ],
  [ 'a1', 'b3', 'c2', 'd3' ],
  [ 'a1', 'b3', 'c2', 'd4' ],
  [ 'a2', 'b1', 'c1', 'd1' ],
  [ 'a2', 'b1', 'c1', 'd2' ],
  [ 'a2', 'b1', 'c1', 'd3' ],
  [ 'a2', 'b1', 'c1', 'd4' ],
  [ 'a2', 'b1', 'c2', 'd1' ],
  [ 'a2', 'b1', 'c2', 'd2' ],
  [ 'a2', 'b1', 'c2', 'd3' ],
  [ 'a2', 'b1', 'c2', 'd4' ],
  [ 'a2', 'b2', 'c1', 'd1' ],
  [ 'a2', 'b2', 'c1', 'd2' ],
  [ 'a2', 'b2', 'c1', 'd3' ],
  [ 'a2', 'b2', 'c1', 'd4' ],
  [ 'a2', 'b2', 'c2', 'd1' ],
  [ 'a2', 'b2', 'c2', 'd2' ],
  [ 'a2', 'b2', 'c2', 'd3' ],
  [ 'a2', 'b2', 'c2', 'd4' ],
  [ 'a2', 'b3', 'c1', 'd1' ],
  [ 'a2', 'b3', 'c1', 'd2' ],
  [ 'a2', 'b3', 'c1', 'd3' ],
  [ 'a2', 'b3', 'c1', 'd4' ],
  [ 'a2', 'b3', 'c2', 'd1' ],
  [ 'a2', 'b3', 'c2', 'd2' ],
  [ 'a2', 'b3', 'c2', 'd3' ],
  [ 'a2', 'b3', 'c2', 'd4' ] ]
于 2013-03-27T20:43:02.387 回答
4

对于未指定数量的数组,您可以这样做:

var arrays = [
  ["a1", "a2"],
  ["b1", "b2", "b3"],
  ["c1", "c2"],
  ["d1", "d2", "d3", "d4"]
];
(function dive(stack) {
  if (stack.length==arrays.length) {
    console.log(stack);
  } else {
    arrays[stack.length].forEach(function(v){
        dive(stack.concat(v));
    });
  }
})([]);

演示(打开控制台)

如果您想支持旧浏览器,请为 forEach使用shim 。

于 2013-03-27T12:10:45.267 回答