-2

I took js-combinatorics code and produced this:

(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());

I expect to get this result in the end:

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

But keep getting Uncaught TypeError: undefined is not a function in Chrome and TypeError: arguments.forEach is not a function in Firefox every time I use forEach in this part of code:

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;
}

Keeping indexes of _ array is a must.

Kevin Kopf
  • 13,327
  • 14
  • 49
  • 66
  • 1
    i really wonder what you're doing there given that a [cartesian product function is quite simple](http://stackoverflow.com/a/15310051/1048572) – Bergi Feb 18 '15 at 23:15

2 Answers2

0

arguments is not an Array, so it doesn't have a forEach method.

You can convert it to an array just like you did in var args = arraySlice.call(arguments);, or you use a for loop to iterate over its elements.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
0

I needed to post the _ array with non-strict indexation:

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

The default solutions are no-go, because they do not handle such arrays. So I had to tweak 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;
}
Community
  • 1
  • 1
Kevin Kopf
  • 13,327
  • 14
  • 49
  • 66