Cartesian product of multidimensional array - javascript

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.

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.

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

Related

Why does Promise.all().then() still make the output synchronous?

I am working on an exercise on Javascript and the point is to make everything work in an asynchronous way. The exercise goes like this: To have an array that is to be filled with random numbers. Then the max element of this array will be the length of a rectangular 2D-Array. For every unique element in the array that is to be used as an index in the 2D-array, i must find the sum of the rows and columns in the 2D-array, as well as the sum of the surrounding elements in the 2D-array. These tasks need to be done separately, and i used Promises. But when i log on the console to see how the work is taking place, it still outputs it synchronously, or even worse it starts searching on the arrays even before they are filled. I am new to this, so i need some guidance.
var arrayA = [];
var matricaA = [];
var n=10;
var m;
var arr = [];
var k = 0;
var funcMatrixHolder = [];
var result = [];
function genRandomNum(min,max)
{
return Math.floor(Math.random()*(max-min+1)+min);
}
function fillArray(n) {
return new Promise(function(resolve,reject) {
arrayA = Array.from({length: n}, () => genRandomNum(1,10));
m = arrayA[0];
arrayA.filter(function(pos){
if(pos > m) {
m = pos;
}
resolve(m);
});
});
}
function createMatrix(size) {
return new Promise(function(resolve, reject){
arr = Array.from({length: size}, () => genRandomNum(1,10));
//console.log(arr);
resolve(arr);
});
}
function sumRowCol(matrix, len, arr) {
return new Promise(function(resolve, reject) {
var shuma=0;
arr.filter(function(elem, pos) {
var poz = elem-1;
if(arr.indexOf(elem) === pos) { //per cdo element unik
for(var k = 0; k<len; k++){
sum+=matrix[k][poz];
sum+=matrix[poz][k];
//console.log(k);
//
}
}
resolve(sum);
console.log(sum+" sum"); //to check how it works
sum=0;
})
});
}
function sumNr(myArray, arr) {
return new Promise(function(resolve, reject){
var sum = 0;
arr.filter(function(elem, pos) {
var rowLimit = myArray.length-1;
var columnLimit = myArray[0].length-1;
var i = elem-1;
var j = elem-1
if(arr.indexOf(elem) === pos) { //per cdo element unik
for(var x = Math.max(0, i-1); x <= Math.min(i+1, rowLimit); x++) {
for(var y = Math.max(0, j-1); y <= Math.min(j+1, columnLimit); y++) {
if(x !== i || y !== j) {
sum += myArray[x][y];
//
}
}
}
console.log(sum + "sum");
resolve(sum);
sum = 0;
}
})
})
}
fillArray(n).then(function(result) {
//filled array and got it's max
});
while(k<m) {
funcMatrixHolder.push(createMatrix(m));
k++;
}
//console.log(funcMatrixHolder);
Promise.all(funcMatrixHolder).then(function(result) {
matricaA = result;
});
Promise.all([sumNr(matricaA,arrayA),sumRowCol(matricaA,m,arrayA)]).then(function(result){
console.log(result);
});
Just in case, this is the answer that got approved as correct:
(Excuse the non-english labels)
var arrayA = [];
var matricaA = [];
var n=10;
var m;
var arr = [];
var k = 0;
var funcMatrixHolder = [];
var result_final = [];
var filterArr = [];
var result_final_final = [];
function genRandomNum(min,max)
{
return Math.floor(Math.random()*(max-min+1)+min);
}
function fillArray(n) {
return new Promise(function(resolve,reject) {
arrayA = Array.from({length: n}, () => genRandomNum(1,10));
m = arrayA[0];
arrayA.filter(function(elem, pos){
if(elem > m) {
m = elem;
}
if(arrayA.indexOf(elem) === pos) {
filterArr.push(elem);
}
});
var fArrPH = {
max: m,
fArr: filterArr
}
resolve(fArrPH);
});
}
function createMatrix(size) {
return new Promise(function(resolve, reject){
arr = Array.from({length: size}, () => genRandomNum(1,10));
//console.log(arr);
resolve(arr);
});
}
function fillArrayFunction(size) {
return new Promise(function(resolve, reject) {
for (var i=0; i<size; i++){
funcMatrixHolder.push(createMatrix(size));
}
resolve(funcMatrixHolder);
})
}
function shumaRreshtKolone(matrix, index, madhesia) {
let shuma=0;
//console.log(madhesia);
for(var k = 0; k<madhesia; k++){
//console.log(index);
//index = 10;
shuma+=matrix[k][index];
shuma+=matrix[index][k];
}
console.log("ShumaRreshtKolone u llogarit.");
return shuma;
}
function sumNrRrethues(myArray, index) {
var sum = 0;
var rowLimit = myArray.length-1;
var columnLimit = myArray[0].length-1;
var i = index-1;
var j = index-1
for(var x = Math.max(0, i-1); x <= Math.min(i+1, rowLimit); x++) {
for(var y = Math.max(0, j-1); y <= Math.min(j+1, columnLimit); y++) {
if(x !== i || y !== j) {
sum += myArray[x][y];
}
}
}
console.log("ShumaNrRrethues u llogarit");
return sum;
}
var m1;
function job() {
return new Promise(function(resolve,reject) {
fillArray(n).then(function(result) {
//console.log("array", result);
m1 = result;
return fillArrayFunction(result.max);
}).then(function(result) {
Promise.all(result).then(function(result) {
matricaA = result;
console.log(matricaA);
console.log(arrayA);
m1.fArr.map(function(item) {
//console.log("item", item);
return result_final.push({
Elementi: m1.fArr.indexOf(item),
ShumaRreshtKolone: shumaRreshtKolone(matricaA,item-1,m1.max),
ShumaNrRrethues: sumNrRrethues(matricaA, item-1)
});
});
resolve(result_final);
}).catch(err => {
reject(err);
})
})
})
}
job().then(function(result){
console.log(JSON.stringify(result));
}).catch(err => {
console.log(err);
})

want to add AND search to this incremental search plugin

I want to add AND search function to a following incremental search jQuery plugin that can search option elements from select-boxes.
JSFiddle
I'm trying to do these ideas but can't code successfully.
- first of all I want to define white space as a delimiter.
- next I want to distinguish that variable from other white spaces in option elements.
By the way, I don't want to replace a lot of DOM elements.
So, I don't want to use plugin like selectize.js, nether datalist elements anyway.
Somebody help?
(function ($, window, document, undefined) {
'use strict';
var pluginName = "selectboxsearch",
defaults = {
delay: 100,
bind: 'keyup',
};
function Plugin(element, target, options) {
this.element = element;
this.$element = $(element);
this.target = target;
this.options = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.vars = {
optionRows: $(this.target).children().map(function () {
return this;
})
};
this.init();
}
Plugin.prototype = {
init: function () {
var self = this,
delay = this.options.delay;
this.$element.on(this.options.bind, function () {
var timeout = window.setTimeout(function () {
self.go();
}, delay);
});
},
go: function () {
var array = this.vars.optionRows,
val = this.$element.val();
//一周目のみ
for (var n = 0; n < 1; n++) {
// いったん削除
$(this.target).children().remove();
for (var i = 0, len = array.length; i < len; i++) {
if (array[i]) {
//option内のスペースを除去
var pos = array[i].innerHTML.toLowerCase().replace(/ /g,'').indexOf(val, 0);
// キーワードが空、もしくはヒットした場合要素追加
if ((val.replace(/ /g,'').length === 0) || pos >= 0) {
$(this.target).append(array[i]);
}
}
}
}
},
additem: function (items) {
var self = this,
array = this.vars.optionRows,
len = this.vars.optionRows.length;
$.each(items, function (index, item) {
var add = true;
for (var i = 0, len; i < len; i++) {
if (item.value == array[i].value) {
add = false;
}
}
if (add == true) {
array.push(item);
}
});
this.vars.optionRows = array;
self.go();
},
delitem: function (items) {
var self = this,
array = [];
$.each(this.vars.optionRows, function (index, item) {
var del = false;
for (var i = 0, len = items.length; i < len; i++) {
if (item.value == items[i].value) {
del = true;
}
}
if (del == false) {
array.push(item);
}
});
this.vars.optionRows = array;
self.go();
}
};
$.fn[pluginName] = function (target, options) {
return this.each(function () {
if (!$.data(this, "plugin_" + pluginName)) {
$.data(this, "plugin_" + pluginName, new Plugin($(this), target, options));
}
});
};
function _fnGetMaxLenString(settings, colIdx) {
var s, max = -1,
maxIdx = -1;
for (var i = 0, ien = settings.aoData.length; i < ien; i++) {
s = _fnGetCellData(settings, i, colIdx, 'display') + '';
s = s.replace(__re_html_remove, '');
s = s.replace(' ', ' ');
if (s.length > max) {
max = s.length;
maxIdx = i;
}
}
return maxIdx;
}
})(jQuery, window, document);

context in function in object method

There is piece of code:
var object = {
findById: function(idNumber) {
var data = this.childNodes;
var returnItems = {};
function callback(node) {
if (parseInt(node.id) === idNumber)
returnItems = node;
};
function iterator(node, callback) {
callback(node);
var nodes = node.childNodes;
if (nodes === undefined) {
return;
};
for (var i = 0; i < nodes.length; i++) {
var iterNode = nodes[i];
iterator(iterNode, callback);
};
};
function bind(func, context) {
return function() { // (*)
return func.apply(context, arguments);
};
};
for (var i = data.length - 1; i >= 0; i--) {
iterator(data[i], callback);
};
return returnItems;
},
}
How to import context in to iterator and callback function?
if I put console.log(this) into function iterator() - this will be 'window', but not my object.
Also it shouldn't be this.callback this.iterator etc.
As I understand it should be like call/apply or bind.
How do it?
Copy a reference to this inside the findById function.
var object = {
findById: function(idNumber) {
var data = this.childNodes;
var returnItems = {};
// assign this to a variable
// you can use inside the nested functions
var that = this;
function callback(node) {
if (parseInt(node.id) === idNumber)
returnItems = node;
};
function iterator(node, callback) {
callback(node);
var nodes = node.childNodes;
if (nodes === undefined) {
return;
};
for (var i = 0; i < nodes.length; i++) {
var iterNode = nodes[i];
iterator(iterNode, callback);
};
};
function bind(func, context) {
return function() { // (*)
return func.apply(context, arguments);
};
};
for (var i = data.length - 1; i >= 0; i--) {
iterator(data[i], callback);
};
return returnItems;
}
};
Use call or apply.
for (var i = data.length - 1; i >= 0; i--) {
iterator.call(this, data[i], callback);
};
wherever you use functions do it this way:
functionToCall.apply(this,params); //this or the context you want to have inside
Sample:
function callable() {
console.log(this);
}
callable(); //logs window
callable.apply({}); //logs {}

Infinite loop in list iterator

I created a list iterator but when trying traverse a list backward the loop runs infinitely. What I did wrong?
function List() {
this.listSize=0;
this.pos=0;
this.dataStore =[];
this.append = append;
this.currPos = currPos;
this.end = end;
this.front = front;
this.length = length;
this.moveTo = moveTo;
this.next = next;
this.prev = prev;
}
function append(element) {this.dataStore[this.listSize++]=element;}
function currPos() {return this.pos;}
function end() {this.pos = this.listSize-1;}
function front() {this.pos =0;}
function length() {return this.listSize;}
function moveTo(position) {this.pos = position;}
function prev() {if(this.pos > 0) --this.pos;}
function next() {if(this.pos < this.listSize) ++this.pos;}
var names = new List();
names.append("A"); names.append("B"); names.append("C");
for(names.end(); names.currPos() >= 0; names.prev()) {console.log(names.getElement());}
Your loop only terminates when the current list position is less than zero, but your .prev() function won't allow that to happen.
To fix it? Well, that's a matter of opinion, but if you're going to the trouble of implementing a list class you might as well make a native .forEach function:
function forEach(callback) {
for (var i = 0; i < this.listSize; ++i)
callback(this.dataStore[i], i);
}
Then you can do:
names.forEach(function(name) { console.log(name); });
I ran into a similar problem when trying to implement a list ADT from the book "Data Structures and Algorithms" and came to find out that the author re-wrote that section in later versions to look like this:
module.exports = List;
function List() {
this.listSize = 0;
this.pos = 0;
this.dataStore = [];
this.clear = clear;
this.find = find;
this.toString = toString;
this.insert = insert;
this.append = append;
this.remove = remove;
this.front = front;
this.end = end;
this.prev = prev;
this.next = next;
this.length = length;
this.currPos = currPos;
this.moveTo = moveTo;
this.getElement = getElement;
this.length = length;
this.contains = contains;
this.hasNext = hasNext;
this.hasPrevious = hasPrevious;
this.insertIf = insertIf;
}
function append(element) {
this.dataStore[this.listSize++] = element;
}
function find(element) {
for (var i = 0; i < this.dataStore.length; ++i) {
if (this.dataStore[i] === element) {
return i;
}
}
return -1;
}
function remove(element) {
var foundAt = this.find(element);
if (foundAt > -1) {
this.dataStore.splice(foundAt, 1);
--this.listSize;
return true;
}
return false;
}
function length() {
return this.listSize;
}
function toString() {
return this.dataStore;
}
function insert(element, after){
var insertPos = this.find(after);
if(insertPos > -1){
this.dataStore.splice(insertPos+1, 0, element);
++this.listSize;
return true;
}
return false;
}
function clear() {
delete this.dataStore;
this.dataStore = [];
this.listSize = this.pos = 0;
}
function contains(element) {
for (var i = 0; i < this.dataStore.length; ++i) {
if(this.dataStore[i] === element) {
return true;
}
}
return false;
}
function front() {
this.pos = 0;
}
function end() {
this.pos = this.listSize-1;
}
function prev() {
return this.dataStore[--this.pos];
}
function next(){
return this.dataStore[this.pos++];
}
function hasNext(){
if (this.pos > this.listSize -1) {
return false;
} else {
return true;
}
}
function hasPrevious() {
if(this.pos <= 0) {
return false;
} else {
return true;
}
}
function currPos() {
return this.pos;
}
function moveTo(position) {
this.pos = position;
}
function getElement() {
return this.dataStore[this.pos];
}
function insertIf(element) {
var greaterThan = true;
for(this.front(); this.hasNext(); ){
if(this.next() > element) {
greaterThan = false;
break;
}
}
console.log(element);
if(greaterThan){
this.append(element);
return true;
} else {
return false;
}
}
Your loops will then look like this:
for (list.front(); list.hasNext();) {
var listItem = list.next();
if(listItem instanceof Customer) {
console.log(listItem.name + ", " + listItem.movie);
} else {
console.log(listItem);
}
}
This has proven to be a much more reliable implementation so you may want to consider switching to this.
You need to change your for loop to:
for(names.end(); names.currPos() > 0; names.prev())

JS: How to return 'undefined' instead of throwing error 'cannot read property x of undefined'

What is the best way to have js return undefined rather than throw an error when a parent property does not exist?
Example
a = {}
b = a.x.y.z
// Error: Cannot read property 'value' of undefined
// Target result: b = undefined
You have to check for the existence of each property:
var b;
if (a.x && a.x.y && a.x.y.z) {
b = a.x.y.z
}
Or, simliar to another poster's "safeGet" function:
var get = function (obj, ns) {
var y = ns.split('.');
for(var i = 0; i < y.length; i += 1) {
if (obj[y[i]]) {
obj = obj[y[i]];
} else {
return;
}
}
return obj;
};
Use:
var b = get(a, 'x.y.z');
try {
a = {}
b = a.x.y.z
}
catch (e) {
b = void 0;
}
I would go for slightly verbose:
var b = ((a.x || {}).y || {}).z
you could write a safeGet helper function, something like:
edited for drilldown as suggested in comments by arcyqwerty
var getter = function (collection, key) {
if (collection.hasOwnProperty(key)) {
return collection[key];
} else {
return undefined;
}
};
var drillDown = function (keys, currentIndex, collection) {
var max = keys.length - 1;
var key = keys[currentIndex];
if (typeof collection === 'undefined') {
return undefined;
}
if (currentIndex === max) {
return getter(collection, key);
} else {
return drillDown(keys, currentIndex + 1,
getter(collection, key));
}
};
var safeGet = function (collection, key) {
if (key.indexOf(".") !== -1) {
return drillDown(key.split("."), 0, collection);
} else {
return getter(collection, key);
}
};
a = { x: 1 };
b = safeGet(a, 'x.y.z');
http://jsfiddle.net/YqdWH/2/

Categories