Nodejs : The array is changed without reference to change. Why? - javascript

Sorry I'm new to node js. If you look at the ListComp array it has changed after the while loop. Could someone explain what is wrong with this code?
function FormGrp() {
var ListOne = [];
var ListTwo = [];
var count = 0;
var Control;
var graph = [];
var ListComp = [[59],[73,41],[52,40,9],[26,53,6,34],[10,51,87,86,81]];
Control = 4;
console.log(ListComp);
while(Control != 0){
ListOne = ListComp[count];
ListTwo = ListComp[count+1];
for(var i=0; i<ListOne.length; i++){
for(var j=0; j<ListTwo.length; j++){
if(j === 2){
ListTwo.shift();
break;
}
graph.push([ListOne[i],ListTwo[j]]);
}
}
count++;
Control--;
}
console.log('\n',ListComp);
}
In the two console outputs the values ​​were different, but I did not use any mocking method in the ListComp array, how could it have been changed?

It changes because objects are copied by reference, and in Javascript an Array is an object. So, if you change the copy the original one is going to be affected as well.
Take into account that ListComp is an array of arrays, which means that if you copy one of those arrays in ListComp you are copying them by reference. For example in this line:
ListOne = ListComp[count]
In the first iteration you are copying the array [59] by reference to the array ListOne.
Let's see an example with just a simple array:
const arr = [1, 2, 3];
const arrCopy = arr;
arrCopy.push(4)
console.log(arr); // [1, 2, 3, 4]
console.log(arrCopy); // [1, 2, 3, 4]
A fast way to solve it is using, for example, Array#slice() to clone the arrays:
ListOne = ListComp[count].slice();
ListTwo = ListComp[count+1].slice();
But maybe structuring your code in a way you don't need to create clones could be better though.

Related

How to get unique values from two 2D arrays in JavaScript

I am trying to get unique values from two arrays which looks like that:
array[{A,B,C},{C,D,E},{1,3,2},....]
both looks the same.
I tried to add them using concat and the get unique values from looping.
So I ended up with this:
function uniqueValues() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = ss.getSheetByName("arr1");
const array1 = srcSheet.getRange(1, 1, srcSheet.getLastRow(), srcSheet.getLastColumn()).getValues();
var srcSheet1 = ss.getSheetByName("arr2");
const array2 = srcSheet1.getRange(1, 1, srcSheet1.getLastRow(), srcSheet1.getLastColumn()).getValues();
var dodaj = array1.concat(array2);
for (var i=0; i<dodaj.length; i++) {
var listI = dodaj[i];
loopJ: for (var j=0; j<dodaj.length; j++) {
var listJ = dodaj[j];
if (listI === listJ) continue;
for (var k=listJ.length; k>=0; k--) {
if (listJ[k] !== listI[k]) continue loopJ;
}
dodaj.splice(j, 1);
}
}
var result = ss.getSheetByName("test").getRange(2, 5, dodaj.length, 3).setValues(dodaj);
//Logger.log(dodaj);
}
It was working well when array looked like this array[{A,B},{C,D}] but with three elements it started to return duplicates as well... I have no idea what can be wrong.
If I understand you correctly, you want to retrieve the unique rows from the values in arr1 and arr2. That is to say, you want to remove duplicate inner arrays from dodaj.
After using concat to merge the two arrays, you could do the following:
Use JSON.stringify() to transform each inner array to a string, in order to compare them without iterating through them.
Use the Set constructor and the spread syntax in order to remove the duplicate strings (see this answer).
Transform the strings back to arrays with JSON.parse().
Code snippet:
var dodaj = array1.concat(array2);
dodaj = [...new Set(dodaj.map(JSON.stringify))].map(JSON.parse);
var result = ss.getSheetByName("test").getRange(2, 5, dodaj.length, dodaj[0].length).setValues(dodaj);

'push' element to the subarray within nested array

I have listed several ways to create nested array and add value to sub array:
Way 1: works!
// Create empty nested array:
var arrs = [[],[],[]];
arrs[0].push(1);
arrs[1].push(2);
arrs[2].push(3);
Then, not surprisingly, arrs is updated:
[[1],[2],[3]]
Way 2: works!
var arrs = [];
for (var i = 0; i < 3; i++) {
arrs[i] = [];
}
arrs[0].push(1);
arrs[1].push(2);
arrs[2].push(3);
arrs:
[[1],[2],[3]]
Way 3: ?
var arrs = [];
var subArr = [];
for (var i = 0; i < 3; i++) {
arrs[i] = subArr;
}
arrs[0].push(1);
arrs[1].push(2);
arrs[2].push(3);
arrs:
[[1,2,3],[1,2,3],[1,2,3]]
My question: why the way 3 leads to arrs result as [[1,2,3],[1,2,3],[1,2,3]] rather than [[1],[2],[3]]?
In your third way, you are assigning each element of arrs to the same array by reference: subArr. There is no copying, all three items in arrs point to the same value in memory.
Naturally, when you push to arrs[0], you are then pushing to subArr. Repeat 3 times, and you then have the result you are experiencing.
Because it's the same object!
If you did
arrs[i] = [];
You'd get a different result! You'd assign a new array each time instead of a reference to one array.
This is an easy trap to fall into in any programming language.

Combining elements of 2 dimentional array

I have an JavaScript array:
var arr = [["A",["05",90]],["A",["04",240]],["A",["03",235]],["B",["00",123]],["B",["01",234]]];
I want final array to look like:
var final = [["A",[["05",90],["04",240],["03",235]]],["B",[["00",123],["01",234]]]];
The final array is formed by combining all the 2nd element of 2 dimensional array when the 1st element matches.
Please advice how can this be achieved in JavaScript
Object keys are generally the easiest way to create groups like this
var tmp = {}; // temporary grouping object
// loop over data
arr.forEach(function (item) {
// check if group started
if (!tmp.hasOwnProperty(item[0])) {
tmp[item[0]] = [];
}
// push data to group
tmp[item[0]].push(item[1]);
});
// map temp object to results array
var results = Object.keys(tmp).map(function (key) {
return [key, tmp[key]];
});
DEMO
If you start with the array you gave:
var arr = [["A",["05",90]],["A",["04",240]],["A",["03",235]],["B",["00",123]],["B",["01",234]]];
then create a new array to store the values:
var final = [];
and simply combine all of the third-level elements (such as ["05",90] and ["01",234]) of each second-level ones (such as "A" and "B") by looping through the array:
for(var i = 0; i < arr.length; i++) {
var found = false;
for(var j = 0; j < final.length; j++) {
if(arr[i][0] == final[j][0]) {
final[j][1].push(arr[i][1]);
found = true;
break;
}
}
if(!found) {
final[final.length] = [arr[i][0], [[arr[i][1][0], arr[i][1][1]]]];
}
}
This is essentially a sorting method: if the "key" is equal to one in the final array, then it adds it to that one. If not, then appends it to the end of final.
Here's the working example on JSFiddle: link.
This outputs the array:
["A", [["05", 90], ["04", 240], ["03", 235]]], ["B", [["00", 123], ["01", 234]]]
as requested.
Also, as #PaulS commented, it would be recommended to use Objects instead as Strings, to make them Key-Value pairs. But in my answer I stuck with arrays.

How to sort object values in JavaScript when keys are numbers?

let's say I have such weird code:
var weirdo = {};
var ids = [10, 30, 11, 1, 4, 2];
var producers = ['Ford','Rover','BMW','Fiat','Renault','Mitsubishi'];
var n = producers.length;
for(var i=0; i<n; i++) {
weirdo[ids[i]] = producers[i];
}
// unknown code ???
How to sort weirdo by values? It's not array and no, I can't sort producers before filling weirdo.
Any ideas?
Oh, and relation id <=> producer is VERY IMPORANT!
You can use an array of objects:
var items = [
{id:10, producer:'Ford'},
{id:30, producer:'Rover'},
{id:11, producer:'BMW'},
{id:1, producer:'Fiat'},
{id:4, producer:'Renault'},
{id:2, producer:'Mitsubishi'},
]
// or, starting from your two arrays:
var items = [];
for (var i=0; i<ids.length && i<producers.length; i++)
items[i] = {id:ids[i], producer:producers[i]};
Then you can sort that array by id:
items.sort(function(a, b){ return a.id-b.id; });
...and iterate it with a for-loop.
Another solution would be an iterator array, to loop over an id<->producer object (weirdo) in the correct order:
var weirdo = {"10":"Ford","30":"Rover",...};
var ids = Object.keys(weirdo); // if not already built somewhere
ids.sort(function(a,b){return a-b;}); // sort numeric
// loop:
for (var i=0; i<ids.length; i++) {
var id=ids[i], producer=weirdo[id];
...
}
The short answer is that objects are unordered by spec. The properties of an object are just that - properties. They are served as you request them, they are not items to be moved around within the object.
How an object is visualized upon inspection is entirely up to the agent performing the visualization. For instance, if you were to write the following in Chrome
console.log({ x: 1, a: 2 });
... it would display the parameters in alphabetical order. That is not something innate to the object, but simply a matter of chrome implementation.
If you would, instead, write the following in chrome
for(key in { x: 1, a: 2 }) console.log(key);
... it would log an x, followed by an a, i.e. showing the properties for the same object in the order that they were added.
You could of course make sure that you add the properties to your object in the alphabetical/numerical order of their respective property names, but that would be missing the point, as there is no guarantee that all implementations will preserve the order of adding either.
Have you tried using Array.Sort?
http://jsfiddle.net/gRoberts/mXwdN/
var weirdo = {};
var producers = ['Ford','Rover','BMW','Fiat','Renault','Mitsubishi'];
producers.sort();
console.log(producers);
producers.map(function(item, index) {
this[index] = item;
}, weirdo);
console.log(weirdo);
Edit: Due to question being updated whilst I was working on a solution, please find an updated version based on the updated question:
http://jsfiddle.net/gRoberts/mXwdN/1/
var weirdo = {};
var ids = [10, 30, 11, 1, 4, 2];
var producers = ['Ford','Rover','BMW','Fiat','Renault','Mitsubishi'];
ids.sort();
ids.map(function(item, index) {
weirdo[item] = producers[index];
}, weirdo);
console.log(weirdo);​
​

How to empty an javascript array?

var arr = [-3, -34, 1, 32, -100];
How can I remove all items and just leave an empty array?
And is it a good idea to use this?
arr = [];
Thank you very much!
If there are no other references to that array, then just create a new empty array over top of the old one:
array = [];
If you need to modify an existing array—if, for instance, there's a reference to that array stored elsewhere:
var array1 = [-3, -34, 1, 32, -100];
var array2 = array1;
// This.
array1.length = 0;
// Or this.
while (array1.length > 0) {
array1.pop();
}
// Now both are empty.
assert(array2.length == 0);
the simple, easy and safe way to do it is :
arr.length = 0;
making a new instance of array, redirects the reference to one another new instance, but didn't free old one.
one of those two:
var a = Array();
var a = [];
Just as you say:
arr = [];
Using arr = []; to empty the array is far more efficient than doing something like looping and unsetting each key, or unsetting and then recreating the object.
Out of box idea:
while(arr.length) arr.pop();
Ways to clean/empty an array
This is perfect if you do not have any references from other places. (substitution with a new array)
arr = []
This Would not free up the objects in this array and may have memory implications. (setting prop length to 0)
arr.length = 0
Remove all elements from an array and actually clean the original array. (splicing the whole array)
arr.splice(0,arr.length)

Categories

Resources