Why does splice() change both Arrays? [duplicate] - javascript

This question already has answers here:
Why does changing an Array in JavaScript affect copies of the array?
(12 answers)
Closed 6 years ago.
Look at the following code:
var x = [1, 2, 3], y;
y = x;
y.splice(0,0,4);
which gives:
y = [4, 1, 2, 3] // (correct)
x = [4, 1, 2, 3] // (why did this change too?)
Why did the x array change when I called .splice() on y?

Objects (including arrays) are passed by reference (effectively, this is what it does... -- purists may disagree with this statement). The splice method mutates the original array. Therefore, since x and y point at the same array, a splice on y will change x as well. To do a shallow clone of x in to y, do y = x.slice(). (Note that any objects within x won't be cloned; they'll be passed by reference.)
var a = [1,2,3];
var b = a;
a[0] = 42;
alert(b[0]); // will show 42
var c = a.slice(); // explicitly makes a copy
a[1] = 6502;
alert(c[1]); // will show 2, not 6502
Taken from value type reference type object in javascript

Related

change index in one array in accordance with another one js [duplicate]

This question already has answers here:
Sort two arrays the same way
(12 answers)
Closed 18 days ago.
I need to change indexes of elements in arr a due to their indexes in arr b.
const a = [4,3,2,1,5];
const b = [1,2,3,4,5];
console.log(a) [1,2,3,4,5]
If you mean ordering array a according to array b, then you can do like this:
a.forEach((element,i) => {
// first get the index of a[i] from array b
const index = b.indexOf(a[i])
// then swap them
const temp = a[index];
a[index] = a[i];
a[i] = temp;
})
You could sort by using the other array as index. If this daoes not work with real data, please andd a small amount of data to highlight the problem.
const
a = [4, 3, 2, 1, 5],
b = [1, 2, 3, 4, 5];
a.sort((l, r) => b[l - 1] - b[r - 1]);
console.log(...a);

How to update a variable without updating its former equal in JavaScript [duplicate]

This question already has answers here:
Why does changing an Array in JavaScript affect copies of the array?
(12 answers)
Closed 2 years ago.
Let's say I have this code:
var arr = [1, 2, 3, 4, 5];
var arr1 = arr;
arr.splice(Math.min(...arr), 1);
But for some reason, the value of arr is the same as arr1. What if I want arr to be different than arr1 and be independent of its updating?
Your issue is this line:
var arr1 = arr;
According to the situation you describe you want to copy the array.
But with this line you're just assigning it to another variable instead of copying.
So in fact, without copying, the arrays are the same.
In order to copy just do something like this:
let copy = array.slice(0);
/* or (will not work for large arrays) */
let copy = [...array];
This should do the trick for you
var arr = [1, 2, 3, 4, 5];
var arr1 = arr.slice();
arr.splice(Math.min(...arr), 1);
console.log(arr);
console.log(arr1);
Arrays are objects, so you can copy them the same way
var x = [1, 2, 3],
y = Object.assign([], x);
x[0] = 16;
console.log(x);
console.log(y);

Swap entire arrays in Javascript

When I try to make a function to swap 2 arrays, the original arrays are left unaltered.
function swap(x, y) {
var temp = x; x = y; y = temp;
}
u=[1, 0];
v=[0, 1];
swap(u, v);
console.log(u);
console.log(v);
This results in u as [1, 0] and v as [0, 1]. The values haven't been changed after the function call to swap.
On the other hand, if I do this without a function call:
u=[1, 0];
v=[0, 1];
var temp = u;
u = v;
v = temp;
console.log(u);
console.log(v);
Then they're swapped correctly, with u as [0, 1] and v as [1, 0].
I thought Javascript arrays are passed by reference, not by value. Am I misunderstanding something here?
Javascript does not have the ability to pass a reference to the u and v variables themselves. So, no assignment to x or y in your swap() function will change what is assigned to u or v. Javascript passes a reference to the object that u and v hold. Thus, you can't change the u and v variables from within swap(). You can change the contents of the object that they point to and thus properties of the object that u and v point to can be modified.
Since I have a C/C++ background, I think of what Javascript does when passing objects as "pass by pointer". When you call swap(u, v), what is passed to the swap() function is a pointer to the array that u also points to. So, now you have two variables u and x both "pointing" at the same array. Thus, if you modify that actual array, then since u points at that same array, both will see the modification. But, nothing you do inside the swap() function can change what object u or v actually point to.
In Javascript, the only way to change what object the original variables point to is to make them properties of an object and pass the object like this:
function swap(obj, x, y) {
var temp = obj[x]; obj[x] = obj[y]; obj[y] = temp;
}
var container = {};
container.u = [1, 0];
container.v = [0, 1];
swap(container, "u", "v");
console.log(container.u);
console.log(container.v);
If you don't mind rewriting both arrays from scratch, you can copy all the contents of one array to a temporary, then copy one array over to the other and then copy the temporary array contents back to the first original. This is not very efficient and there is probably a better way to solve your original problem, but it can be done.
function swap(x, y) {
// remove all elements from x into a temporary array
var temp = x.splice(0, x.length);
// then copy y into x
x.push.apply(x, y);
// clear y, then copy temp into it
y.length = 0;
y.push.apply(y, temp);
}
Getting the terminology on these "reference/value" questions is tricky, but I will do my best.
What you have for your Object / Array variables are really just references. Unlike C++, saying "x = y" does not actually copy the object's variables over to a new memory location. Internally, it's just copying a pointer location over. The language does not have constructions to "automatically recreate" something like an object or array in a new instance; if for some reason, you want to maintain two copies of an array, you will need to explicitly create it then copy over values (ie, = []; or = new Array(); or a copying function like = oldArray.map(...))
A little code example that might conceptually help. These same rules apply between objects and arrays.
a = {}; // In case you haven't seen it, this is like shorthand of "new Object();"
b = {};
c = b;
console.log(a === b); // false
console.log(b === c); // true
b.property = "hello";
console.log(c.property) // hello
Just like Java, JavaScript is pass-by-value only. Assigning to local variables in a function never has any effect on anything outside the function.
They are passed by reference, but they are also assigned by reference. When you write x = y you aren't modifying either of the arrays, you're just making your local variable x refer to the same array as y.
If you want to swap the array contents, you have to modify the arrays themselves:
function swap(x,y) {
var temp = x.slice(0);
x.length = 0;
[].push.apply( x, y );
y.length = 0;
[].push.apply( y, temp );
}
Feb 2022 Solution to Swap 2 Entire Array Contents.
You can use destructuring to swap the 2 arrays:
let a = [ 1, 2, 3, 4 ];
let b = ['a','b','c','d'];
[a,b] = [b,a]; // swap
console.log(a); // ["a", "b", "c", "d"]
console.log(b); // [1, 2, 3, 4, 5]
let a = [ 1, 2, 3, 4 ];
let b = ['a','b','c','d'];
[a,b] = [b,a]; // swap
console.log(a); // ["a", "b", "c", "d"]
console.log(b); // [1, 2, 3, 4, 5]
To swap 2 arrays you may use
Version 1
let arrA = [1,2,3,4];
let arrB = ['Eve', 'Bar', 'Foo'];
let tempArr = [arrA, arrB]; // constructing new array
arrA = tempArr [1];
arrB = tempArr [0];
Version 1 (shorthanded)
let arrA = [1,2,3,4];
let arrB = ['Eve', 'Bar', 'Foo'];
// RHS : construction a new array
// LHS : destruction of array
[arrB, arrA ] = [arrA, arrB];
Version 2 (spread operator)
let arrA = [1,2,3,4];
let arrB = ['Eve', 'Bar', 'Foo'];
let arrC = [...arrB]
arrB = [...arrA]
arrA = [...arrC]

JavaScript: Slice an array into three (roughly) equal arrays [duplicate]

This question already has answers here:
Splitting a JS array into N arrays
(23 answers)
Closed 8 years ago.
How do I slice an array like this:
var a = [1, 2, 3, 4, 5, 6 , 7, 8];
into thirds (ie. three arrays, like this):
[1, 2, 3]
[4, 5, 6]
[7, 8]
Here's what I've got so far:
var first = a.slice(0, Math.ceil(a.length / 3));
var seconds = ???
var third = ???
This works, though it can be cleaned up:
var m, n;
var first, second, third;
m = Math.ceil(a.length / 3);
n = Math.ceil(2 * a.length / 3);
first = a.slice(0, m);
second = a.slice(m, n);
third = a.slice(n, a.length);
First, get the length. Nice and simple: a.length
Next, divide by three and round up. This will be the size of your pieces.
Finally, use a.slice() with appropriate arguments to get the resulting arrays.
Write some code using the above algorithm, and let us know if you have any more specific problems :)

Javascript object reference breaks after changing initial object's value

I am trying to understand a point of confusion I have with JavaScript objects. Specifically, I am interested in finding what, if anything, causes an object reference to break.
To demonstrate the phenomenon, I have included a copy of some output from Chrome's JavaScript console. Note that I am working with arrays here, but we would expect objects to behave similarly given the subtle distinction between arrays and objects in JS. I have added comments for clarity.
// Set x to some array literal
> x = [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
// Set y to x
> y = x
[1, 2, 3, 4, 5]
> x
[1, 2, 3, 4, 5] // as expected
> y
[1, 2, 3, 4, 5] // as expected
As demonstrated above, both x and y output the expected value. Now I shuffle the values of x using a function called shuffle (specified at the bottom of this question).
// Shuffle x
> x = shuffle(x)
[5, 1, 4, 2, 3]
> x
[5, 1, 4, 2, 3] // x changes as expected
> y
[5, 1, 4, 2, 3] // y changes as expected
Again, everything works as expected above. The variables x and y have maintained reference to the same object. However, when we repeat this operation, the results are strange.
// Shuffle x
> x = shuffle(x)
[3, 1, 5, 4, 2]
> x
[3, 1, 5, 4, 2] // x changes as expected
> y
[5, 1, 4, 2, 3] // y didn't change this time
Below is the shuffle function, adapted from here. Its purpose is to shuffle the contents of an array (parameter r1) and to return the first n items of the mixed array.
function shuffle(r1,n) {
var i = r1.length, j, tempi, tempj, r2;
r2 = r1;
while (--i) {
j = Math.floor(Math.random() * (i + 1));
tempi = r2[i];
tempj = r2[j];
r2[i] = tempj;
r2[j] = tempi;
}
return r2.slice(0,n);
}
I have since fixed the problem by rewriting my shuffle function based on this function. However, I would still like to understand what's going on. For a quick look at the code in action, I have made a jsFiddle.
Any ideas? I appreciate your time.
If you remove the .slice(0,n);, it will behave the way you expect. slice makes a new array.
So the first time you call shuffle, within your loop you modify the array x = y = r1 = r2. Then you make a copy of it on that last line and assign that to x. Now x !== y, but they contain the exact same elements. You can test that they are distinct objects after your first call to shuffle:.
The next time you call shuffle you are shuffling the copy of x you made and y is untouched.
.slice() makes a shallow copy of the Array, and so you're overwriting x with a new Array.
// The original was shuffled, but now `x` is a new Array
x = shuffle(x);
That's why y showed the first shuffle (because you hadn't sliced it yet), but none thereafter. The subsequent shuffle was on the overwritten x, and y still references the original.
If you wanted to truncate the original Array, just change its .length.
So instead of this:
return r2.slice(0,n);
Do this:
r2.length = n;
...though you're not passing anything to n currently.

Categories

Resources