Algo Problem Statement: Find the smallest array that adds up to the target sum.
Code Issue: I do not understand the difference in results when:
- using the arr.push() method
vs.
- using the Spread syntax
Please reference the ment line below.
The Spread syntax returns the correct solution, while the .push() method keeps on pushing onto the same array. I don't understand why it keeps referencing the same array in memory.
Many thanks in advance!
let howSum = (target, arr, memo = {}) => {
if (target in memo) return memo[target];
if (target === 0) return [];
if (target < 0) return null;
let smallest = null;
for (let e of arr) {
if (howSum(target - e, arr, memo) !== null) {
let result = howSum(target - e, arr, memo);
// result.push(e);
result = [...result, e];
if (smallest === null || result.length < smallest.length) {
smallest = result;
}
}
}
memo[target] = smallest;
return smallest;
};
console.log(howSum(10, [1, 2, 5])); // [5, 5]
Algo Problem Statement: Find the smallest array that adds up to the target sum.
Code Issue: I do not understand the difference in results when:
- using the arr.push() method
vs.
- using the Spread syntax
Please reference the ment line below.
The Spread syntax returns the correct solution, while the .push() method keeps on pushing onto the same array. I don't understand why it keeps referencing the same array in memory.
Many thanks in advance!
let howSum = (target, arr, memo = {}) => {
if (target in memo) return memo[target];
if (target === 0) return [];
if (target < 0) return null;
let smallest = null;
for (let e of arr) {
if (howSum(target - e, arr, memo) !== null) {
let result = howSum(target - e, arr, memo);
// result.push(e);
result = [...result, e];
if (smallest === null || result.length < smallest.length) {
smallest = result;
}
}
}
memo[target] = smallest;
return smallest;
};
console.log(howSum(10, [1, 2, 5])); // [5, 5]
Share
Improve this question
asked Dec 17, 2020 at 23:34
PmcorreaPmcorrea
751 gold badge1 silver badge6 bronze badges
4
-
5
result = [...result, e];
creates a new array. It's not due to using spread specifically, it's simply becauseresult = [ ]
assigns a new array toresult
. – Felix Kling Commented Dec 17, 2020 at 23:38 - 4 Well, the answer to "I don't understand why it keeps referencing the same array in memory" is that it's by design. If used appropriately, there is a lot of utility in mutating objects instead of creating new ones. – Nick Commented Dec 17, 2020 at 23:43
- @FelixKling, thank you. Can you elaborate a little more? The endgame is to update the array with the addition of a new element. Don't both methods acplish updating the older array? I can either update the same array, or create a new array with the updated value. – Pmcorrea Commented Dec 17, 2020 at 23:51
-
1
I guess if you don't create a new array then every
memo[target]
entry refers to one and the same array, meaning the memoized solution for eachtarget
is exactly the same, which is obviously conceptually wrong. – Felix Kling Commented Dec 18, 2020 at 0:13
2 Answers
Reset to default 11array.push(element)
vs. array = [...array, element]
Array.push
adds an element to the end of the existing array while the spread syntax creates an entirely new array. For example, the following code will throw an error because we are trying to redefine a const
:
const array = ["foo", "bar"];
array = [...array, "baz"]; // Uncaught TypeError: invalid assignment to const 'array'
Array.push
adds to an existing array, so there is no need to redefine:
const array = ["foo", "bar"];
array.push("baz"); // No error; "baz" is successfully added to the end of the array.
Another difference is speed. array.push(element)
is ~2,500 times faster than array = [...array, element];
As pointed out by @FelixKling, the spread syntax itself does not create a new array. You can also use the spread syntax in a function like this: myFunction(...myArray)
. This will use the array elements as arguments. So in other words, ...myArray
will not create a new array, but [...myArray]
will. Just a small detail worth noting.
Why your loop keeps referencing the same array in memory
The Spread syntax returns the correct solution, while the .push() method keeps on pushing onto the same array. I don't understand why it keeps referencing the same array in memory.
Objects in JavaScript (JavaScript arrays are objects) are reference types—not value types. Therefore, using the spread syntax, you create a new array (result
), but still supply the old array (arr
) to your function. When you use Array.push
, you modify the array that was supplied to your function. And since you modify the array that was supplied (instead of creating a local one), you will keep calling your function with new values in the array. When you use the spread syntax, you create a new array (so result
doesn't reference the arr
array), and when you call your function with the arr
parameter, you still have the same values as when you first called the function.
@trincot wrote a neat break down of what is going on in your code.
Here is an experiment you can do in a JavaScript console:
const myArray = ["foo", "bar"];
function changeArray(arrayParameter) {
const arrayVariable = arrayParameter;
// We are still referencing the array that was supplied to our function, so
// although it looks like we tried to duplicate the array, arrayVariable.push,
// arrayParameter.push, and myArray.push will all modify the same array.
arrayVariable.push("baz");
}
changeArray(myArray);
console.log(myArray); // ["foo", "bar", "baz"]
the
.push()
method keeps on pushing onto the same array. I don't understand why it keeps referencing the same array in memory.
If we take the variant of your code where you don't use the spread syntax, but push
, then realise that:
push
mutates the array, it doesn't create a new one- The only place where your code creates a new array is at
return []
So, look at what happens after that return []
:
result.push(e);
will alter that array into[e]
.- The first time
smallest
is null, sosmallest
bees a reference to that single array. - Another reference is made to that single array at
memo[target]
- This reference is returned to the caller, which assigns it to
result
. - A new value is pushed to that single array, which now has two elements. And here it es:
- As the above mentioned
memo[target]
references the same array asresult
, you have actually mutated thatmemo[target]
:memo[target].length
will now be 2.
This is undesired. Once you have assigned an array to memo
it should never mutate. This is why at some point in your code you should make a new array.