多维数组的笛卡尔积

Cartesian product of multidimensional array

我使用 js-combinatorics 代码生成了这个:

(function(global) {
    'use strict';
    if (global.Combinatorics) return;
    /* common methods */
    var addProperties = function(dst, src) {
        Object.keys(src).forEach(function(p) {
            Object.defineProperty(dst, p, {
                value: src[p]
            });
        });
    };
    var hideProperty = function(o, p) {
        Object.defineProperty(o, p, {
            writable: true
        });
    };
    var toArray = function(f) {
        var e, result = [];
        this.init();
        while (e = this.next()) result.push(f ? f(e) : e);
        this.init();
        return result;
    };
    var common = {
        toArray: toArray,
        map: toArray,
        forEach: function(f) {
            var e;
            this.init();
            while (e = this.next()) f(e);
            this.init();
        },
        filter: function(f) {
            var e, result = [];
            this.init();
            while (e = this.next()) if (f(e)) result.push(e);
            this.init();
            return result;
        }

    };
    /* Cartesian Product */
    var arraySlice = Array.prototype.slice;
    var cartesianProduct = function() {
        if (!arguments.length) throw new RangeError;
        var args = arraySlice.call(arguments);
        args = args[0];
        console.log(args);
        var
            size = args.reduce(function(p, a) {
                return p * a.length;
            }, 1),
            sizeOf = function() {
                return size;
            },
            dim = args.length,
            that = Object.create(args, {
                length: {
                    get: sizeOf
                }
            });
        if (!size) throw new RangeError;
        hideProperty(that, 'index');
        addProperties(that, {
            valueOf: sizeOf,
            dim: dim,
            init: function() {
                this.index = 0;
            },
            get: function() {
                if (arguments.length !== this.length) return;
                var result = [];
                arguments.forEach(function(element,index,array) {
                    var i = arguments[index];
                    if(i >= this[index].length) return;
                    result.push(this[index][i]);
                });
                return result;
            },
            nth: function(n) {
                var result = [];
                arguments.forEach(function(element,index,array) {
                    var l = this[index].length,
                        i = n % l;
                    result.push(this[index][i]);
                    n -= i;
                    n /= l;
                });
                return result;
            },
            next: function() {
                if (this.index >= size) return;
                var result = this.nth(this.index);
                this.index++;
                return result;
            }
        });
        addProperties(that, common);
        that.init();
        return that;
    };

    /* export */
    addProperties(global.Combinatorics = Object.create(null), {
        cartesianProduct: cartesianProduct
    });
})(this);

var _ = [];
_[1] = [1,4];
_[7] = [2,9];

cp = Combinatorics.cartesianProduct(_);
console.log(cp.toArray());

我希望最终得到这样的结果:

[[1,2],[1,9],[4,2],[4,9]]

但是每次我在这部分代码中使用 forEach 时,都会在 Chrome 和 Firefox 中得到 Uncaught TypeError: undefined is not a functionTypeError: arguments.forEach is not a function

nth: function(n) {
    var result = [];
    arguments.forEach(function(element,index,array) {
        var l = this[index].length,
            i = n % l;
        result.push(this[index][i]);
        n -= i;
        n /= l;
    });
    return result;
}

必须保留 _ 数组的索引。

arguments 不是数组,因此它没有 forEach 方法。

您可以像在 var args = arraySlice.call(arguments); 中那样将其转换为数组,或者使用 for 循环遍历其元素。

我需要 post 具有非严格索引的 _ 数组:

var _ = [];
_[1] = [1,4];
_[7] = [2,9];

默认解决方案是行不通的,因为它们不处理此类数组。所以我不得不调整 Bergi's idea found here:

function cartesian(arg) {
    var r = [], max = arg.length-1;
    function helper(arr, i) {
        while(typeof arg[i] === "undefined") {
            i += 1;
        }
        for (var j=0, l=arg[i].length; j<l; j++) {
            var a = arr.slice(0); // clone arr
            a.push(arg[i][j]);
            if (i==max) {
                r.push(a);
            } else
                helper(a, i+1);
        }
    }
    helper([], 0);
    return r;
}