Difference of two 2D arrays - javascript

I am trying to make function to get me difference of two 2D arrays but I found that to make function removeArray() work it's required to take different counter variables in both function. If it's taken i in both than loop iterate only once where it should iterate twice.
function removeArray(toremove, myarray){
for(i=0; i< toremove.length ; i++){
// console.log(getIndex(toremove[i],myarray));
myarray.splice(getIndex(toremove[i],myarray),1);
console.log("" + myarray); //only [2,3] will get remove
}
}
function getIndex(array, myarray){
for(i=0;i< myarray.length ; i++){
// if(typeof(array)== 'undefined'){console.log("error"); return 100;}
if((myarray[i][0] == array[0]) && (myarray[i][1] == array[1])){
return i;
}
}
}
var myarray=[[1,1],[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[2,4],[3,1],[3,2],[3,3],[3,4],[4,1],[4,2],[4,3],[4,4]];
var toremove=[[2,3],[3,3]];
removeArray(toremove,myarray);
Also when commented parts are included(both together) i.e, // console.log(getIndex(toremove[i],myarray)) and // if(typeof(array)== 'undefined'){console.log("error"); return 100}it iterates infinitely where it should have not more than twice.
Why is it so? Pls help. Thanks in advance!

The problem is that you do not define i with var or let. In that case i is a global variable and is shared by the two functions.
So when the nested getIndex function is called, i potentially increments until myarray.length. Then when execution comes back inside the first function's loop, i is already too great to continue looping. The loop there exits and all is done.
Instead define i as a local function variable (var) or block variable (let) and it will work:
function removeArray(toremove, myarray) {
for(let i = 0; i < toremove.length; i++) {
myarray.splice(getIndex(toremove[i], myarray), 1);
}
}
function getIndex(array, myarray){
for(let i = 0; i < myarray.length; i++){
if (typeof(array)== 'undefined') {
console.log("error");
return 100;
}
if ((myarray[i][0] == array[0]) && (myarray[i][1] == array[1])) {
console.log("found match at position " + i);
return i;
}
}
}
var myarray=[[1,1],[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[2,4],[3,1],[3,2],[3,3],[3,4],[4,1],[4,2],[4,3],[4,4]];
var toremove=[[2,3],[3,3]];
console.log("before: " + JSON.stringify(myarray));
removeArray(toremove,myarray);
console.log("after: " + JSON.stringify(myarray));
Usually the better practice is to not mutate an array with splice, but to return a new copy without the items to be removed. You can use filter and every for that. And then you must assign the function's return value to the array that should have the result (could also overwrite the same array):
function removeArray(toremove, myarray){
return myarray.filter(arr =>
toremove.every(rem => arr[0] != rem[0] || arr[1] != rem[1])
);
}
var myarray=[[1,1],[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[2,4],[3,1],[3,2],[3,3],[3,4],[4,1],[4,2],[4,3],[4,4]];
var toremove=[[2,3],[3,3]];
console.log("before: " + JSON.stringify(myarray));
myarray = removeArray(toremove, myarray);
console.log("after: " + JSON.stringify(myarray));

Maybe .filter method be good for you
function removeArray(toremove, myarray) {
return myarray.filter((el) => {
for (let i in toremove) {
if (toremove[i][0] === el[0] && toremove[i][1] === el[1]) {
return false;
}
}
return true;
});
}
var myarray=[[1,1],[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[2,4],[3,1],[3,2],[3,3],[3,4],[4,1],[4,2],[4,3],[4,4]];
var toremove=[[2,3],[3,3]];
console.log(removeArray(toremove,myarray));

It is iterating once because your code is getting into an error. javascript always passes variable by reference. You can refer this to understand
Uncaught TypeError: Cannot read property '0' of undefined on line 16
you can use below logic to avoid error
function removeArray(toremove, myarray){
let indexes = []
for(i=0; i < toremove.length ; i++){
indexes.push(getIndex(toremove[i],myarray))
}
for (var i = indexes.length -1; i >= 0; i--)
myarray.splice(indexes[i],1);
}

Related

Scope issue in recursive Javascript function

I have a recursive function (performing Heap's algorithm to generate permutations). It seems to have a variable scope issue.
function permute(starting_arr) {
var all_permutations = [];
heap(starting_arr, starting_arr.length-1);
console.log(all_permutations);
return all_permutations;
function heap(a, n) { // a = array, n = max index i.e. length -1
var temp_an;
if (a.length-1 == n) {
all_permutations.push(a);
}
if (n>1) {
heap(a.slice(), n-1);
}
for ( var i=0; i<n ; i++ ) {
temp_an = a[n];
if (n%2==0) {
a[n] = a[0]
a[0] = temp_an;
} else {
a[n] = a[i]
a[i] = temp_an;
}
all_permutations.push(a);
if (n>1) { heap(a.slice(), n-1); }
}
}
}
It seems the problem is the "all_permutations.push(a)" because the thing works if I replace that with ...
all_permutations.push([]);
for ( var g=0 ; g<a.length ; g++ ) {
all_permutations[all_permutations.length-1][g] = a[g];
}
And as you can see I'm trying to use slice, which I've read about as a solution allowing you to pass the array by value rather than reference, such as in this ...
function x(arr){
arr.push(4);
}
var a = [1,2,3]
x(a);
console.log(a);
var b = [1,2,3]
x(b.slice());
console.log(b);
That does something but it still doesn't work properly.
Thanks for any help.
as you can see I'm trying to use slice, which I've read about as a solution allowing you to pass the array by value rather than reference
Yes, you found the problem and the correct approach for solving it. However you need to specifically apply it to the line
all_permutations.push(a);
in your for loop:
all_permutations.push(a.slice());

Initializing a variable while concatenating another one

I have this for loop with variable value_from_db
for (var i = 0; i < arrayLength; i++) {
var value_from_db = array[i].value;
}
However I need to make the variable value_from_db_0, value_from_db_1, value_from_db_2 ... depending on i.
Something like:
var value_from_db_+i = array[i].value;
The purpose is
for (var i = 0; i < arrayLength; i++) {
if( array[i].condition == '0' ) {
jQuery("#username").on('change', function() {
var value = this.value;
if( value === array[i].value ) { //because array[i].value doesnot seem to work here
count++;
alert(count);
}
}
}
because array[i].value doesnot seem to pass through the anonymous function, I am trying to differentiate the varialbe.
You have a couple of options here. The first obvious one is to use an array:
var value_from_db = array.map(item => item.value)
// then access them with the index directly
console.log(value_from_db[0])
But if you really want those variable names, you could house them within an object fairly easily:
var myObj = {}
array.forEach((item, i) => myObj[`value_from_db_${i}`] = item.value)
// the use with something like
console.log(myObj.value_from_db_0)
After reading the comments on #Igors closure answer, it looks like what you are trying to do (and this is best guess from the vague comment), is watch for changes to #username, and figure out if all the array values have been matched at one point or another. If I'm correct, you could do it like this:
// remove unwanted condition items
var conds = array.filter(item => item.condition === '0')
// watch for element changes
jQuery("#username").on('change', function() {
var comparer = this.value
// update a match key for any items where a match is found
conds
.filter(item => item.value === comparer)
.forEach(item => item.match = true)
// check if all matches have been found
if(conds.every(item => item.match)){
alert('all matched')
}
})
After edit of the question this became an entirely different issue that has to do with closure and captured variable.
Potentially repeating calls jQuery("#username").on('change', ... look suspicious, but maybe there is only one array[i].condition == '0' in the array.
for (var i = 0; i < arrayLength; i++) {
if( array[i].condition == '0' ) {
jQuery("#username").on('change', (function(aValue) {
return function() {
var value = this.value;
if (value === aValue) {
count++;
alert(count);
}
};
})(array[i].value));
}
}

JSHint warning "Function declared within loop referencing an outer scope variable may lead to confusing semantics" . How can I improve the code?

JSHint shows the error:
"Function declared within loop referencing an outer scope variable may lead to confusing semantics".
How can I improve the following code to get rid of the warning?
var getPrecedence = function getPrecedence(operator, operators) {
var keys = Object.keys(Object(operators));
for (var i = 0, len = keys.length; i < len; i++) {
var check = Object.keys(operators[keys[i]]).some(function (item) {
return item === operator;
});
if (check) return operators[keys[i]][operator];
}
};
You are supposed not to use the function expression inside the loop body, but instead declare it outside:
function getPrecedence(operator, operators) {
function isOperator(item) {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
return item === operator;
}
var keys = Object.keys(Object(operators));
for (var i = 0, len = keys.length; i < len; i++) {
var check = Object.keys(operators[keys[i]]).some(isOperator);
// ^^^^^^^^^^
if (check) return operators[keys[i]][operator];
}
}
Of course the whole thing could be simplified by just using includes instead of some, and find instead of the loop:
function getPrecedence(operator, operators) {
var keys = Object.keys(Object(operators));
var opkey = keys.find(key =>
Object.keys(operators[key]).includes(operator)
);
if (opkey) return operators[opkey][operator];
}
And finally, Object.keys(…).includes(…) can be simplified to operator in operators[key].
Add it before calling the function, this one will bypass that check
/* jshint -W083 */

For-loop order (with asynchronous function)

I have this code :
exports.formatDepArrTables = function(jsonReturn, type, placeName, callback) {
let toSend = "";
if (type == 'departure') {
for (let j = 0; j < jsonReturn.departures.length; j++) {
console.log("DEPARTURES LOOP j = " + j + "/" + jsonReturn.departures.length);
if(currentDeparture.display_informations.links[0] === undefined) {
toSend += ""; // setting some string informations
}
else {
let oceTrainId = ""; // random number given by a json
_this.getDisruptionFromDisruptionId(oceTrainId, function(data) {
for(let i = 0; i < data.disruptions[0].impacted_objects[0].impacted_stops.length; i++) {
if(currentImpactedStop.stop_point.label == placeName) {
toSend += "string";
}
}
});
}
}
console.log("End of the first loop");
return callback(toSend);
} else if (type == 'arrival') {
// copy&paste
} else {
throw new Error("not defined");
}
};
When I run this code (I use NodeJS), it makes 1/10, 2/10... from the first loop but it didn't iterate the second loop on the 1st iteration of the first loop (and it shows "End of the first loop" and starts the second loop).
getDisruptionFromDisruptionId is a custom method which makes a request (with 'request' NodeJS module) on an API.
Of course, I need to have informations given by getDisruptionFromDisruptionId to run my next loop...
Parent function of this code part is returning a callback that needs to be "filled" at the end of the both two loops.
Any ideas ?
request is async function, you need to add async / await to your code or use recursion

Find variable value

I have some inputs in my app: <_input code/> + <_input code/> = <_input code/>.
Let's imagine first input name is a, appropriately second and third inputs' names are b and c. I filled my inputs:
7 + x = 12
Is there any way to calculate x value?
What do I want from my script:
It finds variable in inputs' values.
It checks all fields of my form filled properly.
It finds variable in inputs' values.
From given information script calculates value of variable.
How many inputs will be doesn't matter. I just want to find value of x. Is there any library to do this?
function calculcateA(b,c){
return c-b;
}
if(inputA === 'x'){
alert(calculateA(inputB,inputC));
}
And so on... there is nothing wrong with this functions, but I want to automate this proccess like WolframAplha.
The best thing for you, I guess would be to find some library for solving equations. If you are in need to solve bigger sets of equations then maybe something related to linear algebra.
Can't really tell you an exact solution so you will have to search for yourself.
Here is some code that should solve the problem.
function calculate() {
var varIndex = -1;
//Ensure that at least two three arguements are passed
if (arguments.length < 3) {
throw "You need at least three parameters to make an equation";
}
//Make sure that there is only one variable
for (var i = 0; i < arguments.length; i++) {
if (isNaN(arguments[i])) {
if (varIndex != -1) {
throw "You can't have two variables";
return;
}
varIndex = i;
}
}
//If variable has been found
if (varIndex != -1) {
var answer = 0;
//If variable is at the last position, add all constants
if (varIndex == types.length - 1) {
for (var j = 0; j < arguments.length - 1; j++) {
answer = answer + j;
}
} else {
//Otherwise Deduct all values from the last
answer = arguments[arguments.length - 1];
for (var k = 0; k < arguments.length - 1; k++) {
if (k == varIndex) { continue; }
answer = answer - j;
}
}
//Return Result
return { variable: arguments[varIndex], answer: answer };
}
else {
throw "You need at least one variable";
return;
}
}
You would use the above as follows:
var a = document.querySelector("input[name=a]");
var b = document.querySelector("input[name=b]");
var c = document.querySelector("input[name=c]");
var calcBtn = document.getElementById("calculate");
calcBtn.addEventListener("click", function () {
try {
var result = calculate(a.value, b.value, c.value);
console.log("The value of " + result.variable + " is " + result.answer);
} catch (e) {
console.log(e);
}
});

Categories