Object.assign works not as expected for 2-dimensional arrays - javascript

Starting from a 2 dimensional array M
let M = [[1,1],[1,1]];
I would expect the code
let N = Object.assign([], M);
to create a copy of M. In other words to my understanding of Object.assign I should now have two identifiers M,N pointing to different locations in memory, with both locations containing the same 2-dimensional array.
However when I mutate an entry of N, the same entry in M changes as well:
N[0][0] = 0;
console.log(N);
console.log(M);
gives
> Array [Array [0, 1], Array [1, 1]]
> Array [Array [0, 1], Array [1, 1]]
Why is that? A analog example works as expected if M is a list instead of a list of lists.

I tried Array.from() as Andreas suggested, didn't make it work.
I finished creating a deep copy in a custom method:
export function copy(array: any[]): any[] {
const result = Object.assign([], array)
for (let [key, val] of Object.entries(result)) {
if (Array.isArray(val)) {
result[key] = copy(val)
}
}
return result;
}

Related

why empty slots are being replaced with undefined while cloning array using spread syntax?

I'm creating a clone array from an array that contain some empty slots. But after cloning it is being replaced with undefined. If the source array contain some empty slots then clone array should also contain same number and at exact same position empty slots. I don't get the reason. I'm using spread syntax to clone array as:
const arr = [1, "", , null, undefined, false, , 0];
console.log('arr => ', arr);
const clone = [...arr];
console.log('clone => ', clone)
Output is as below in chrome console
Using spread syntax will invoke the object's iterator if it has one. The array iterator will:
a. Let index be 0.
b. Repeat
Let len be ? LengthOfArrayLike(array).
iii. If index ≥ len, return NormalCompletion(undefined).
(...)
1. Let elementKey be ! ToString(𝔽(index)).
2. Let elementValue be ? Get(array, elementKey).
(yield elementValue)
vi. Set index to index + 1.
And the length of a sparse array is still the index of the last element plus one:
const arr = [];
arr[5] = 'a';
console.log(arr.length);
So, even with sparse arrays, spreading them will result in the new array containing values of:
arr[0]
arr[1]
arr[2]
// ...
arr[arr.length - 1]
even when the original array has empty slots in between 0 and arr.length - 1.
If you want empty slots, spreading will only work if you delete the undesirable indices afterwards - or iterate over the array manually, only assigning indices you need.
const arr = [1, "", , null, undefined, false, , 0];
console.log('arr => ', arr);
const clone = [];
for (let i = 0; i < arr.length; i++) {
if (arr.hasOwnProperty(i)) {
clone[i] = arr[i];
}
}
console.log('clone => ', clone)
But you could also consider restructuring your code to avoid sparse arrays entirely - they're not very intuitive.
Let's take a step back
let x;
console.log(x); // undefined
console.log(typeof x); // undefined
If you don't define a variable, it is un-defined.
Let's see now an empty array:
let x = [,]; // even [] would work but I thought this one is clearer for some
console.log(x[0]); // undefined
console.log(typeof x[0]); //undefined
Why is that? Simply because
If you don't define a variable, it is un-defined.
above answers already made it pretty clear why you getting undefiend.
Just to add more If you log arr[2] you will get undefined, i haven't read it anywhere but from what i know spread operator spread the values of array/obj that is why arr[2] value is undefiend

Array, return original index from a sorted array in javascript

'I wish to sort an array in numerical order but once it is sorted I wish to be able to find the original index.
For example the original array:
ptsGP = [3,8,2,5,6,9,8,4]
I am using the following code below to sort the array:
arr = ptsGP;
var arr2 = arr.map(function(o, i){return {idx: i, obj: o}; }).sort(function(a, b) {
return b.obj - a.obj;
});
for(var i = 1, j = arr2.length; i <= j; i++){
document.write('i:' + i + ' = arr2[i].obj: PTS: ', arr2[i-1].obj+"<br/>");
}`
This is fine as the sorted array is :
arr = [2,3,4,5,6,8,8,9];
How can I find the index of sorted number in the original array? In this case it would be :
Index on original array would be = [2,0,7,3,4,1,6,5]
I know I could use map on the original array but how can I deal with duplicate numbers i.e, in this case I have two number 8's within the array?
You can achieve it by following below steps :
Creating a deep copy of an original array by using spread operator. So that we can get proper indexing.
Now we can iterate deep copy array to get the index of the elements from an original array.
Regarding duplicate values we can check via .indexOf() and .lastIndexOf() methods.
via and then via comparison. For fetching the correct index of duplicate values I wrote a logic based on the count of duplicate value.
Working Demo :
// Original array.
const originalArray = [3, 8, 2, 5, 6, 9, 8, 4];
// Creating a deep copy of an original array.
const deepCopy = [...originalArray].sort(function(a, b){
return a-b
});
// result array
const arr = [];
// count to get the index based on duplicate values.
let count = 0;
// Iterating deepCopy array to get the actual index.
deepCopy.forEach((elem) => {
// Checking for duplicate value in an array
if (originalArray.indexOf(elem) === originalArray.lastIndexOf(elem)) {
// This line of code execute if there is no duplicates in an array.
arr.push(originalArray.indexOf(elem))
} else {
// This line of code execute if there is duplicate values in an array.
count++;
// Inserting the index one by one.
arr.push(originalArray.indexOf(elem, count))
}
});
// Result array.
console.log(arr);

How can I made new array from firsts elements of arrays from an array

How can I made new array from firsts elements of arrays from this array ?
[["1",2],["3",2],["6",2]]
and I want it to be
['1', '3', '6']
My attempt:
var newArray = []
for (i = 0; i < arrayToCompare.length - 1; i++) {
newArray.push(arrayToCompare[[0]])
}
You could just use a simple map and destructure the first element:
const arr = [["1", 2],["3", 2],["6", 2]]
console.log(arr.map(([e]) => e))
The ([e]) part of that before the => is destructuring the parameter using array destructuring. It means that for each subarray passed to the map callback, e receives the value of the first element of the subarray. In ES5 and earlier, the ([e]) => e arrow function would be function(entry) { return entry[0]; }
Still, if you still don't understand the concept, prefer efficiency, or just want to go back to basics, you could use the trusty for loop, making sure to push only the first element of each subarray:
const arr = [["1", 2],["3", 2],["6", 2]]
const output = []
for (let i = 0; i < arr.length; i++) {
output.push(arr[i][0])
}
console.log(output)
Try this:
let arr = [["1", 2], ["3", 2], ["6", 2]];
let res = arr.map(val => {
return val[0]
})
console.log(res);
You can use Array.prototype.map() to crate a new array with the item from the first index:
var arr = [["1",2],["3",2],["6",2]]
var newArray = arr.map(i => i[0]);
console.log(newArray);
This one also works
console.log(Object.keys(Object.fromEntries([["1", 2],["3", 2],["6", 2]])))
In this example, Object.fromEntries will create an object from an array of key/value pairs - it will take the first element as a key, and the second element as the value - creating something like this:
{
"1": 2,
"3": 2,
"6": 2
}
Then, Object.values will grab the keys of the object, thus, removing the values and retaining the keys, giving the desired output.
P/S: just added another way to do this
console.log(Array.from([["1", 2],["3", 2],["6", 2]], x=>x[0]))
Use map and get the first element using shift method.
PS: not very efficient because of ...(spread) operator for each element.
const arr = [["1",2],["3",2],["6",2]];
const arrFirsts = arr.map(items => [...items].shift());
console.log(arrFirsts)
console.log(arr)

Remove array from inside array based on index in JS

I have an array which looks like:-
[[0,1], [0,2], [0,3], [1,1], [1,2]...]
I am looking to remove one of the arrays from this array based on the indexOf() but I keep getting a value of -1, which removes the last item from the array when I try the following code:-
array = [[0,1], [0,2], [0,3], [1,1], [1,2]];
console.log('Removed value', array.splice(array.indexOf([0,3]), 1));
console.log('Result', array);
would somebody be able to point me in the right direction to help solve this issue I am having?
Thank you in advance.
You can't use indexOf because when you declare [0,3] in array.splice(array.indexOf([0,3]), 1)) you're creating a new array and this new object is not inside your array (but rather another array that has the same values).
You can use findIndex instead as follows (example):
array.findIndex(x => x[0] === 0 && x[1] === 3)
this will return 2 - now you can use it to delete:
array.splice(2, 1)
If it is OK to remove every occurrence of [0,3], then consider Array.filter combined with array destructuring of the lambda arguments. It offers a slightly leaner syntax than the other solutions.
const input = [
[0,1],
[0,2],
[0,3],
[1,1],
[1,2]
];
const result = input.filter(([x,y]) => !(x==0 && y==3));
console.log('Result=', result);
To explain why your solution will not work:
Comparison operators only work for values not passed by a reference. When dealing references, comparison operators always return false, unless the two references point to the same object. (See this on MDN)
An example:
a = [0,1]
b = a
b === a //true. a and b point to the same array.
a === [0,1] //false. a points to a different array than [0,1]
b[0] = 2
a[0] //2 - b points to the same array as a
To give you a solution (borrows from here)
//Function to compare the values inside the arrays, and determine if they are equal.
//Note: does not recurse.
function arraysEqual(arr1, arr2) {
if(arr1.length !== arr2.length)
return false;
for(var i = arr1.length; i--;) {
if(arr1[i] !== arr2[i])
return false;
}
return true;
}
array = [[0,1], [0,2], [0,3], [1,1], [1,2]];
//Find the index where x has the same values as [0,3]
array.findIndex(x => arraysEqual(x, [0,3])) //2

looping through an array of arrays

I am just learning Javascript programming and I'm having issues in looping through an array of arrays. I need a coded procedure to go about it.
I want to print out each individual array in the array.
I was trying to use the Map, but once type break it returns the key and value of the first array. I just need a code to help me print out each key and value of every array individually.
var arrOfArr = [
['one', 1],
['two', 2],
['three', 3]
]
var newmap = new Map(arrOfArr)
for (const [key, values] of newmap.entries()) {
newmap.forEach((values, key ) => console.log(key, values))
}
You can simply use a the .forEach method
The forEach() method executes a provided function once for each array element.
This way you can loop through arrOfArr and fill obj with the key/value pairs:
For each array element in arrOfArr you can select the key (first item in the sub array) with e[0] and it's value (second item in the sub array) with e[1].
Then write obj[e[0]] = e[1] to add a new key/value pair in obj
Here is the code:
var arrOfArr = [ ['one', 1], ['two', 2], ['three', 3] ];
const obj = {}
arrOfArr.forEach(e => {
obj[e[0]] = e[1]
})
console.log(obj)
Or if you just want to print them individually, you need obj. Therefore use:
var arrOfArr = [ ['one', 1], ['two', 2], ['three', 3] ];
arrOfArr.forEach( e => console.log(`${e[0]} => ${e[1]}`) )
With ES6 Destructuring assignment you can achieve it with one line:
arrOfArr.forEach(([key, value]) => console.log(key, value));
First, have a look at the below attempt on Node REPL.
Reference: Using iterator on Map() to iterate over keys and values pairs
> var arrOfArr = [
... ['one', 1],
... ['two', 2],
... ['three', 3]
... ]
undefined
>
> var newMap = new Map(arrOfArr)
undefined
> newMap
Map { 'one' => 1, 'two' => 2, 'three' => 3 }
>
> var iteratorObj = newMap[Symbol.iterator]();
undefined
>
> // Printing keys and values
undefined
> for (let item of iteratorObj) {
... console.log(item[0], item[1])
... }
one 1
two 2
three 3
undefined
>
Now, try it online.
var arrOfArr = [
['one', 1],
['two', 2],
['three', 3]
]
var newMap = new Map(arrOfArr)
var iteratorObj = newMap[Symbol.iterator]();
// Printing keys and values
for (let item of iteratorObj) {
console.log(item[0], item[1])
}
arrOfArr is an Array which contains 3 Arrays.
JavaScript arrays are zero-indexed: the first element of an array is at index 0, and the last element is at the index equal to the value of the array's length property minus 1. Using an invalid index number returns undefined.
Useful link : MDN Array
Example:
var arrOfArr = [['one', 1],['two', 2],['three', 3]]
// First array INDEX 0
console.log("First: ", arrOfArr[0]);
// Second array INDEX 1
console.log("Second: ", arrOfArr[1]);
// Third array INDEX 2
console.log("Third: ", arrOfArr[2]);

Categories

Resources