Why my code to clone an array doesn't work JavaScript - javascript

So since JavaScript doesn't let you copy array using "=" I have to write this code. But it doesn't work
let arr = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
var arrclone = [];
for (let x = 0; x < arr.length; x++) {
for (let y = 0; y < arr[x].length; y++) {
arrclone[x][y] = arr[x][y];
}
}
console.log(arrclone);
It said
arrclone[x][y] = arr[x][y];
^
TypeError: Cannot set property '0' of undefined.
How is it undefined both of them are already been declared.
Sorry, I am a beginner sorry if my question seems stupid.

When you start, each row of the array is empty. So initialise it to an empty row of array:
for (let x = 0; x < arr.length; x++) {
// Use this...
arrclone[x] = []; // ========================> You missed this line.
for (let y = 0; y < arr[x].length; y++) {
arrclone[x][y] = arr[x][y];
}
}
FYI, for the right approach, please use Array.slice() (but only for primitive values, see the problem here).

You should ideally be using Array.slice() for copying arrays:
let arr = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
var arrclone = arr.map(e => e.slice());
console.log(arrclone);

Javascript is not a language that makes copies on assignment. It uses references and stores them instead. Here you are literally just copying reference to the data instead of actual data. There are multiple ways to help you with this.
The most simple way is to use
var arrclone = JSON.parse(JSON.stringify(arr))
We can also use array destructuring and it will look something like this:
var arrclone = [...arr]

Related

How to write my reverse function properly?

i have a problem and i need help for this question.
My reverse function doesn't work the way I want it to.
function reverseArrayInPlace(array){
let old = array;
for (let i = 0; i < old.length; i++){
array[i] = old[old.length - 1 - i];
};
};
let arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
I expect on [5, 4, 3, 2, 1] but i have [5, 4, 3, 4, 5].
Why does it work this way? Please help me understand.
P.S I know about the reverse method.
Variable, with assigned object (array, which is a modified object in fact) - stores just a link to that object, but not the actual object. So, let old = array; here you just created a new link to the same array. Any changes with both variables will cause the change of array.
(demo)
let arr = [0,0,0,0,0];
let bubu = arr;
bubu[0] = 999
console.log( arr );
The simplest way to create an array clone:
function reverseArrayInPlace(array){
let old = array.slice(0); // <<<
for (let i = 0; i < old.length; i++){
array[i] = old[old.length - 1 - i];
};
return array;
};
console.log( reverseArrayInPlace( [1, 2, 3, 4, 5] ) );
P.s. just for fun:
function reverseArrayInPlace(array){
let len = array.length;
let half = (len / 2) ^ 0; // XOR with 0 <==> Math.trunc()
for( let i = 0; i < half; i++ ){
[ array[i], array[len - i-1] ] = [ array[len - i-1], array[i] ]
}
return array;
};
console.log( reverseArrayInPlace( [1, 2, 3, 4, 5] ) );
If you're writing a true in place algorithm, it's wasteful from both a speed and memory standpoint to make an unnecessary copy (as other answers point out--array and old are aliases in the original code).
A better approach is to iterate over half of the array, swapping each element with its length - 1 - i compliment. This has 1/4 of the iterations of the slice approach, is more intuitive and uses constant time memory.
const reverseArrayInPlace = a => {
for (let i = 0; i < a.length / 2; i++) {
[a[i], a[a.length-1-i]] = [a[a.length-1-i], a[i]];
}
};
const a = [1, 2, 3, 4, 5];
reverseArrayInPlace(a);
console.log(a);
Since this is a hot loop, making two array objects on the heap just to toss them out is inefficient, so if you're not transpiling this, you might want to use a traditional swap with a temporary variable.
function reverseArrayInPlace(a) {
for (var i = 0; i < a.length / 2; i++) {
var temp = a[i];
a[i] = a[a.length-i-1];
a[a.length-i-1] = temp;
}
};
var a = [1, 2, 3, 4];
reverseArrayInPlace(a);
console.log(a);
You have in old variable the same array (not by value, but by reference), so if you change any of them you'll have changes in both.
So you should create new array, make whatever you want with them and return it (or just copy values back to your origin array if you don't want to return anything from your function).
It happend like that because:
1) arr[0] = arr[4] (5,2,3,4,5)
2) arr[1] = arr[3] (5,4,3,4,5)
....
n) arr[n] = arr[0] (5,4,3,4,5)
So you can just make a copy (let old = array.slice()) and it'll be woking as you'd expect.

Javascript: Arrays built during for loop have their order reset [duplicate]

This question already has answers here:
Why does changing an Array in JavaScript affect copies of the array?
(12 answers)
Closed 4 years ago.
This code seems straightforward enough
let arr = [1,2,3,4,5,6]
let store = [];
for(i = 0; i < arr.length; i++){
console.log(arr)
store.push(arr)
arr.push(arr.shift())
}
console.log('store', JSON.stringify(store))
I'm expecting it to return
[[1,2,3,4,5,6],[2,3,4,5,6,1],[3,4,5,6,1,2],[4,5,6,1,2,3],[5,6,1,2,3,4],[6,1,2,3,4,5]]
But when the loop is complete, it shows
[[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6]]
When printing the values in the console, they appear correct, but when the store variable is logged, they are all reordered.
[1, 2, 3, 4, 5, 6]
[2, 3, 4, 5, 6, 1]
[3, 4, 5, 6, 1, 2]
[4, 5, 6, 1, 2, 3]
[5, 6, 1, 2, 3, 4]
[6, 1, 2, 3, 4, 5]
Why is this occurring?
There is a similar question here, but it doesn't really provide an answer for my case.
Creating a pair of arrays from an array resulting in circular array
Just make sure you are inserting not the same reference to your array:
let arr = [1,2,3,4,5,6]
let store = [];
for(i = 0; i < arr.length; i++){
store.push(Array.from(arr)) // <-- Make sure not the same ref
arr.push(arr.shift())
}
console.log('store', JSON.stringify(store))
store contains the same instance of arr 6 times. You modify it and print it every time, then add the same object to store, then modify it again.
To get your desired behaviour you need to add a new instance every time e.g. by cloning it when you add it.
You could push a copy which does not keep the same object reference.
let arr = [1, 2, 3, 4, 5, 6]
let store = [];
for (i = 0; i < arr.length; i++) {
store.push(arr.slice()) // just take a copy
arr.push(arr.shift())
}
console.log(store.map(a => a.join(' ')))
Alternate approach leaving original array untouched and using splice() to remove beginning elements and concat() to add to the end
let arr = [1,2,3,4,5,6];
let store = arr.map((_,i)=> {
let a = arr.slice();
return i ? a.concat(a.splice(0,i)) : a;
})
console.log(JSON.stringify(store))
On every loop, you are pushing the reference of the array to store
Example:
Loop - reference of arr - 0x112, then store[ i ] = reference to 0x112
At end:
arr - refer to 0x112 - value = [1, 2, 3, 4, 5, 6]
store[ ] = [ref(0x112), ref(0x112), ref(0x112), ref(0x112), ref(0x112), ref(0x112)]
Use this:
let arr = [1,2,3,4,5,6]
let store = [];
for(i = 0; i < arr.length; i++){
console.log(arr)
let newArr = arr.slice();
store.push(newArr)
arr.push(arr.shift())
}
console.log('store', JSON.stringify(store))

loop multiple arrays javascript

I have the following structure:
objet and arrays
I would like to determine if the object has an array with values ​​and if so, save those values ​​by saving those values ​​in another arryar that I will then go through, I have the following up to now:
if (resp.Boutique.length >= 1) {
for (let index = 0; index < resp.Boutique.length; index++) {
this.general.push(resp.Boutique[index]);
}
}
if (resp.Curso.length >= 1) {
for (let index = 0; index < resp.Curso.length; index++) {
this.general.push(resp.Curso[index]);
}
}
if (resp.Deporte.length >= 1) {
for (let index = 0; index < resp.Deporte.length; index++) {
this.general.push(resp.Deporte[index]);;
}
}
but if you have more 'if' elements, I do not think it's the best way.
Any recommendation?
If the properties always contain arrays, then there's no need to test for their length before iterating over them; if they have length 0, no iterations will be performed, so nothing will be pushed to this.general.
But there's a better way - you can simply spread each possibly-empty array into this.general, in a single line:
this.general = [...resp.Boutique, ...resp.Curso, ...resp.Deporte];
If the properties of resp contain only the arrays you want to include in .general, then iterate over the values of resp instead:
this.general = [].concat(...Object.values(resp));
arr.concat(arr1, arr2, arr3 ...)
let arr = [1, 2, 3, 4];
let arr1 = [4, 5, 6, 7];
let arr2 = [7, 8, 9, 10]
console.log(arr.concat(arr1, arr2));

Filtering arrays of complex objects with loops

I have two arrays of complex nexted objects that I'm looking for qualifying values within using loops and if statements as seen below. When I find a qualifying object, I need to filter that object out during the next go around of the loop. I'm trying to do that with an array as you can see here but it isn't working as the array starts over during each iteration of the loop. The following version is a simplified version of my code.
I want to update the values in array2 based on the if statement so that those values are not repeated in the nested loop. Instead my emptyArray remains empty instead of adding values from the array2 as elements of array2 are equal to elements of array.
To be clear, right now emptyArray remains empty and never filters array2. I'd like to see emptyArray collect value 2 at the start of the outer loop's second iteration then I'd like to see emptyArray collect value 4 at the start of the 4th iteration of the outer loop.
I'd want to filter each of these values from array2 as they become part of emptyArray so that they do not set off the if statement during the 6th and 8th iterations of the outer loop. I imagine that emptyArray = [2, 4] and array2 = [6, 8, 10] when the loops are finished.
Bottom line, I need emptyArray to collect the qualifying values and pass them back to var array2 for filtering as the loop processes. Remember this is a simplified version of the arrays, and underscore based solution would be very complicated for me to implement or for you to successfully suggest without much more detail.
My code:
var array = [1, 2, 3, 4, 1, 2, 3, 4];
var array2 = [2, 4, 6, 8, 10];
var emptyArray = [];
for (i = 0; i < array.length; i++){
var something = array[i];
var array2 = _.without(array2, emptyArray);
for (a = 0; a < array2.length; a++){
var value = array2[a];
if(something === value){
emptyArray.push(value);
break;
}
}
}
There are a few things wrong with your code, but the reason why you think that push isn't working is because you are overriding your array2 inside the loop.
The push never gets called because your for loop sees an empty array2 when you are doing var array2 = _.without(array2, emptyArray);
Basically var array2 = _.without(array2 /* this is empty, you just overrode it in this scope */, emptyArray); will always result in an empty array and your for loop will exit because length is array2.length === 0 from the start.
Also, you want to use _.difference instead of _.without
var array = [1, 2, 3, 4, 1, 2, 3, 4];
var array2 = [2, 4, 6, 8, 10];
var emptyArray = [];
for (var i = 0; i < array.length; i++) {
var something = array[i];
array2 = _.difference(array2, emptyArray);
for (var j = 0; j < array2.length; j++) {
var value = array2[j];
if (something === value) {
emptyArray.push(value);
break;
}
}
}
console.log("array2",array2);
console.log("emptyArray", emptyArray);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.js"></script>
array2 [6, 8, 10]
emptyArray [2, 4]
var array = [1, 2, 3, 4, 1, 2, 3, 4];
var array2 = [2, 4, 6, 8, 10];
var emptyArray = [];
for (var i = 0; i < array.length; i++) {
var something = array[i];
for (var j = 0; j < array2.length; j++) {
var value = array2[j];
if (something === value) {
array2 = _.without(array2, value);
break;
}
}
}

Javascript Array.push method issue

I have the following code:
function build_all_combinations(input_array){
array = [1,2,3]
limit = array.length - 1
combo = []
for(i = 0; i<= limit; i++){
splice_value = array.splice(0,1)
push_value = splice_value[0]
array.push(push_value)
console.log(array)
combo.push(array)
}
console.log(combo)
}
Which outputs:
[2, 3, 1]
[3, 1, 2]
[1, 2, 3]
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
The last line should be: [[2, 3, 1],[3, 1, 2],[1, 2, 3]]
I'm obviously not grokking something about the way the array is working. Each individual array is correct, but when I go to push them to the combo array, something is failing along the way. What is it?
Each time you are pushing the same array into the combo array; ie, all the references are pointing to the same instance in memory. So when you update one, you've in reality updated them all.
If you want separate references, you'll need to create separate arrays.
shift and slice are your friends here:
var array = [1,2,3];
var combo = []
for(var i = 0; i<array.length; i++){
array.push(array.shift()); // remove first element (shift) and add it to the end (push)
combo.push(array.slice()); // add a copy of the current array to combo
}
DEMO
jordan002 has given the explanation for this behaviour.
Here's the workaround.
array = [1,2,3]
limit = array.length - 1
combo = []
for(i = 0; i<= limit; i++){
splice_value = array.splice(0,1)
push_value = splice_value[0];
array.push(push_value);
console.log(array);
combo.push(array.concat([]));
}
console.log(combo);
You can store a copy in temp variable.
array = [1,2,3]
limit = array.length - 1
combo = []
for(i = 0; i<= limit; i++){
splice_value = array.splice(0,1)
push_value = splice_value[0];
array.push(push_value);
console.log(array);
var temp = array.slice();
combo.push(temp);
}
console.log(combo)
Reference

Categories

Resources