Nodejs code is not executing as expected - javascript

I am trying the below line of codes. I want to save the numbers after each iteration of outer while loop in an array named sn. But, after each iteration sn contains only the numbers of last iteration. May be I am missing whole concept of sync and async.
function test() {
var numbers = [0, 2, 7, 0];
var check = true;
var sn = [];
var p = 0;
while (check) {
var index = numbers.indexOf(Math.max(...numbers));
var value = Math.max(...numbers);
numbers[index] = 0;
for (var i = value; i > 0; i--) {
var temp = ++index;
index = temp % (numbers.length);
numbers[index] += 1;
}
console.log("numbers", numbers);
if (sn.includes(numbers)) { check = false };
sn.push(numbers);
console.log("hey there=========");
}
}
test();

There is nothing to do with sync or async here.
Here what is happening is that, you are trying to push 'numbers' array to 'sn' array.
Statement is "sn.push(numbers);"
So here we are pushing the Object reference of numbers array to 'sn', means you are not making a copy of numbers array and pushing to 'sn'.
You are just pushing the Memory reference of 'numbers' array.
So during first iteration, 'sn' will have exact value as you calculates.
But during the second iteration 'sn' will have two arrays. But those two values are same and points to the same memory location of 'number'.
So here what you should do is create a clone of 'numbers' array during each iteration.
if (sn.includes(numbers)) { check = false };
var cloneArray = numbers.slice(0);
sn.push(cloneArray);

This if statement: if (sn.includes(numbers)) { check = false }; will never be true because the Array.prototype.includes() method does not accept an array as a parameter; only individual elements. numbers is an array and thus will never be truthy.
If you are trying to see if an array contains a sub-array. The answer that Mild Fuzz has in this stack overflow: Javascript array contains/includes sub array should work.

Related

How to push new elements to an array with undefined index in JavaScript

I want to create array once and then just push values to it with any index , but i get Cannot read property 'push' of undefined error
I have following scenario
var neg = [];
I want to use push randomly with any index
neg[0].push([1,2]);
or
neg[22].push([1,2]);
right now I want to define manually like neg[0] = []; , Is there any one way where i can just push to any index i want ?
Here's a quick way to do exactly what you want.
var arr = [];
(arr[0]=[]).push([1,2]);
console.log(arr)
Also it's safer to check if an array already exists at this index, otherwise it will be replaced with an empty array – the above code will replace the array with an empty one if it already exists.
// creates an array at index 0 only if there's no array at this index.
// pushes an array of [1, 2] to the existing array at 0 index
// or the newly created empty one.
(arr[0] || (arr[0] = [])).push([1, 2]);;
var arr = [];
arr[0] = [1];
(arr[0]||(arr[0]=[])).push(2,3);
console.log(arr)
Push will add elements to the end of an array. For example:
var neg = [];
neg.push(3); //this will add the number 3 to the end of your array
The problem here is your trying to add a value to an undefined element:
var neg = [];
neg[0].push([1,2]); // <-- neg[0] is not defined at this moment, and you're treating it as an array object.
If you define your elements as an array, you will not get such an error:
var neg = [];
neg[0] = [];
neg[22] = [];
neg[0].push([1,2]);
neg[22].push([1,2]);
Alternatively (and this is probably what you're probably looking for), you can set the value for any element of your array with the desired index:
var neg = [];
neg[0] = [1,2];
neg[22] = [1,2];
You are going to have to set it to an empty array before you can push it.
neg[0] = neg[0] || []
neg[0].push([1,2]);
You can specify how large the array will be if you know ahead of time, for example var neg = new Array(40); will create a new array with 40 undefined elements.
Once that is created, you can change the value at any index as long as 0 <= index <= 39.
You can use array.splice(your_index, 0, your_element); to push an element into an array at the given index.

Map where each date holds an array, implementation problem

I would need a structure where each key (Date) holds an array of integers.
I have tried the following but it does not seem to be working.
I create a record with the array and then set all its values to 0, although it still seems they are NaN:
The first statement creates a record as a Date with an associated array of a length defined by a variable.
Dictionary.set(Meteor.jira.formatDate(moment(date),[arrayLenght]);
//initialize the array with 0 values
var i;
for (i = 0; i < arrayLenght; i++) {
Dictionary.set(Meteor.jira.formatDate(moment(date))[i]=0);
}
}
Fill array first, then put it into dictionary.
You can update it's value changing any variable that contains reference to your array.
let Dictionary = new Map();
let arrayLenght = 6;
let key = "2018-11-15" //Meteor.jira.formatDate(moment(date))
let arr = Array(arrayLenght).fill(0);
Dictionary.set(key, arr);
let value = Dictionary.get(key);
console.log(JSON.stringify(value));
value[2] = 1;
value.unshift(33);
arr.unshift(15);
console.log(JSON.stringify(Dictionary.get(key)))

First common element across multiple arrays in Javascript

I need to find the first common element across a group of arrays. The number of arrays may vary, but they are always in sequential order (small->large). My arrays are all properties of myObj.
This is what I have so far:
function compare(myObj,v,j) {
if (myObj[j].indexOf(v)>-1) return true;
else return false;
}
function leastCommon ([1,5]) {
var myObj = { //This is filled by code, but the finished result looks like this
1: [1, 2,...,60,...10k]
2: [2, 4,...,60,...20k]
3: [3, 6,...,60,...30k]
4: [4, 8,...,60,...40k]
5: [5,10,...,60,...50k]
};
var key = [1,2,3,4,5]; //also filled by code
var lcm = myObj[key[key.length-1]].forEach(function(v) { //Iterate through last/largest multiple array
var j=key[key.length-2];
while (j>=0) {
if (compare(myObj,v,j)) { //check to see if it is in the next lower array, if yes, check the next one.
j--;
}
if (j>0 && (compare(myObj,v,j+1))===true) return v; //before the loop exits, return the match
}
});
return lcm;
}
I'm not sure what is wrong, but it is returning undefined.
Note: yes, I know a forEach returns undefined, and I tried modifying my code, and I get a "potential infinite loop" error from my editor. Modified code looks like this:
function leastCommon ([1,5]) {
var myObj = { //This is filled by code, but the finished result looks like this
1: [1, 2,...,60,...10k]
2: [2, 4,...,60,...20k]
3: [3, 6,...,60,...30k]
4: [4, 8,...,60,...40k]
5: [5,10,...,60,...50k]
};
var key = [1,2,3,4,5]; //also filled by code
var lcm = 0;
myObj[key[key.length-1]].forEach(function(v) { //Iterate through last/largest multiple array
var j=key[key.length-2];
while (j>=0) {
if (compare(myObj,v,j)) { //check to see if it is in the next lower array, if yes, check the next one.
j--;
}
if (j>0 && (compare(myObj,v,j+1))===true) lcm = v; //before the loop exits, set lcm = v
}
});
return lcm;
}
I would not use forEach since there is no way to exit from the method when you find the first match/failure. You would need to keep looping. Instead you should look into a regular for loop with every and indexOf. This code also assumes that the array is sorted so smallest number comes first. If not, a simple sort() with a clone of the array can solve that.
//pass in arrays, assumes array is sorted
function getFirstCommon (arrs) {
//Loop over the elements in the first array
for (var i=0; i<arrs[0].length; i++) {
//get the value for the current index
var val = arrs[0][i];
//make sure every array has the value
//if every does not find it, it returns false
var test = arrs.every( function (arr) {
//check the array to see if it has the element
return arr.indexOf(val)!==-1;
});
//If we find it, than return the current value
if (test) {
return val;
}
}
//if nothing was found, return null
return null;
}
//test numbers
var nums = [
[1,2,3,4,5,6],
[2,3,4,5,6],
[3,4,5,6],
[4,5,6,7,8,9],
[6,7,8,9]
];
console.log(getFirstCommon(nums)); //6
var nums2 = [
[1,2,3,4,5,6],
[2,3,4,5,6],
[3,4,5,6],
[4,5,6,7,8,9],
[5,7,8,9]
];
console.log(getFirstCommon(nums2)); //5
var nums3 = [
[1,2,3,4,5,6],
[7,8,9,10,11,12],
[7,8,9,10,11,12]
];
console.log(getFirstCommon(nums3)); //null
The code could be improved where it does not check itself
First of all, you do have an infinite loop. If first compare() fails, you never decrease j, and keep checking the same number.
Second: you key array never decreases, so you always compare two last arrays.

Lodash forEach Associative Array

Is there a forEach loop in Lodash for associative arrays? The function called "forEach", I've found, only works for indexed arrays. For example, if I have an array myArray with values [1, 2, 3], and do
lodash.forEach(myArray, function(index) {
console.log(index);
});
and run the function (in Node), I get the expected result:
1
2
3
However, when I try this with an associative array, it doesn't work:
lodash = require('lodash');
myArray = [];
myArray['valOne'] = 1;
myArray['valTwo'] = 2;
myArray['valThree'] = 3;
lodash.forEach(myArray, function(index) {
console.log('7');
});
As you can see from running this in Node, the callback function doesn't fire even when it includes something other than the array elements. It just seems to skip the loop entirely.
First of all, why does this happen? Second of all, is there another function included in Lodash for this problem, or, if not, is there a way to use the forEach function to accomplish this, without changing the original array in the process?
Lodash has the function forOwn for this purpose. In the second array, if you do
_.forOwn(myArray, function(index) {
console.log(index);
});
you should get the intended result.
I'm still not sure why forEach seems to skip the first function, however, but I believe it may have to do with the array not having a "length". A JavaScript array's length is the highest numbered index it has. For example, an array myOtherArray defined as myOtherArray[999]="myValue" will have a length of 1,000 (because arrays are zero-indexed, meaning they start at 0, not 1), even if it has no other values. This means an array with no numbered indexes, or only negative indexes, will not have a length attribute. Lodash must be picking up on this and not giving the array a length attribute, likely to maintain consistency and performance, thus not rendering any output.
myArray = [];
myArray['valOne'] = 1;
myArray['valTwo'] = 2;
myArray['valThree'] = 3;
lodash.forEach(myArray, function(index) {
console.log('7');
});
An associative array is just a set of key value pairs, which is nothing but a Javascript object.
Above case - myArray.length === 0,
You are just addding properties to the array object, not adding any values to actual array.
Instead initialize your myArray like this and loop through using forIn
var myArray = {};
myArray['valOne'] = 1;
myArray['valTwo'] = 2;
myArray['valThree'] = 3;
lodash.forIn(myArray, function(value, key) {
console.log(key + " : " + value);
});
OR just
var myArray = {
valOne : 1,
valTwo : 2,
valThree : 3
};
lodash.forIn(myArray, function(value, key) {
console.log(key + " : " + value);
});
More about Object as Associative Array here

Force an array to recalcuate length after sort

If you take an array and do the following:
arr = [];
arr[100] = 1;
The length will be 101, which makes sense due to 0-99 being set as undefined
Now if we sort that array: arr.sort() it will look like this: [1, undefined x100] since keys are not preserved. However, the length is still 101, since the undefined have all been moved to the end, instead of removed.
Is this behavior intentional and if so: is there a built-in function that removes undefined and recalculates and why is it intentional?
I am not asking how to write my own function to recalculate length. A sorted array's length can easily be forced with for (x = 0; arr[x] != undefined; x++);arr.length = x;
> arr = [];
> arr[100] = 1;
> The length will be 101, which makes sense due to 0-99 being set as undefined
The array has only one member at 100, it is like:
var arr = { '100': 1, 'length': 101};
Now if we sort that array: arr.sort() it will look like this: [1, undefined x100]
No, it doesn't. It has one member at 0 and a length of 100. There aren't 100 members with a value of 'undefined'.
If you wish to reduce the array to only the defined members, there is no built–in function to do that (i.e. essentially to set the length to the highest index that has a value).
You can only do that by iterating over the array, e.g. by reducing the length from the right until an existing property is reached:
function trimArray(arr) {
var i = arr.length;
while ( !(--i in arr)) {
arr.length -= 1;
}
}
Note that for the above to work properly, the array must be sorted. Also, it modifies the array passed in.
Here's a way to extend Array.prototype with a compress method so an array exists of only the defined members and the length is reset appropriately:
if (!('compress' in Array.prototype)) {
Array.prototype.compress = function() {
var i = 0,
lastExisting = 0,
len = this.length;
do {
if (i in this) {
this[lastExisting++] = this[i];
}
} while (++i < len)
this.length = lastExisting;
}
}
Note that it will not remove members whose value is undefined, only those that don't exists at all. So:
var x = [,,,,1,,,2];
x[20] = void 0;
x.compress()
alert(x + '\n' + x.length); // [1,2,<undefined>], length = 3
Edit
As pointed out by zzzzBov, this can also be done using filter:
var x = x.filter(function(item){return true;});
which will replace x with a new array of only the defined members regardless of their value. It will be non-sparse (or contiguous) and have an appropriate length, e.g.
var x = [,,,,1,,,2];
x[20] = void 0; // set x[20] to undefined, length is 21
x = x.filter(function(item){return true;}); // [2, 3, <undefined>], length = 3
Note that this method will only update the array referenced by x, it will not update any other reference to the same array, e.g.
var x = [,,1];
var y = x; // x and y reference same array
x = x.filter(function(item){return true}); // x is now another array of members
// filtered from the original array
alert(x); // [1] x references a different array
alert(y); // [,,1] y still references the original array
this may be useful behaviour if there is a requirement to keep the original array. In contrast, the compress method modifies the original array:
var x = [,,1];
var y = x; // x and y reference same array
x.compress();
alert(x); // [1] x is a modified version of the original array
alert(y); // [1] y references the same (original) array
I have no idea if there is an intention to add such a method to Array.prototype in future versions of ECMAScript or what it might be called, so a different name might be advisable, say xcompress or similar, to avoid unintended conflict with future versions and to make it obvious that it's a native method, not built–in.
I'm also a bit stumped for a suitable name, since packed and compressed already have defined meanings that are different to non–contiguous, but that seems unwieldy so it's compress for now.
arr = [];
arr[100] = 1;
The code won't set 0-99 to undefined, which it does is only set the key 100 to 1, and length property to 101.
And Array.sort won't change the property length of an array.
After sort, there are two own properties of arr, 0 is 1, and length is still 101.
If you're looking to get around the issue, filter the array once you've sorted it (or filter it before sorting).
var arr;
arr = [];
arr[100] = 1;
arr.sort();
arr = arr.filter(function (item) {
return typeof item !== 'undefined';
});
What's actually happening is that you're overriding the length property, which is used by the Array object to determine where the end of the array is, whether or not the array has that many properties.

Categories

Resources