多维数组的笛卡尔积
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 function
和 TypeError: 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;
}
我使用 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 function
和 TypeError: 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;
}