how does this concat command work with this array? - javascript

I came across this JS problem but I can't figure out the syntax of how it's working, could someone please help to explain? I don't understand the empty square bracket syntax at the start and then how the concat is being applied with another empty square bracket? it's just quite confusing for me.
Appreciate any help to step through this.
let arr = [[1, 2],[3, 4],[5, 6, 7, 8, 9],[10, 11, 12]];
let flattened = [].concat.apply([], arr);
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ]

let arr = [[1, 2],[3, 4],[5, 6, 7, 8, 9],[10, 11, 12]];
let flattened = [].concat.apply([], arr);
*first array*---| |---*second array*
The first array has one goal:
to invoke concat() method with this. Here this is the second array. Then the first array is thrown away
Then apply() method flattens the arr array to one level.
You can check it:
let foo = [0].concat([1,2,3], [[1,2,3]] );
console.log(foo)
UPDATE:
In addition, the first array can be removed:
const arr = [[1, 2],[3, 4],[5, 6, 7, 8, 9],[10, 11, 12]];
const flattened = Array.prototype.concat.apply([], arr);
console.log(flattened)
Some info how apply() works.
In addition, it would be really useful to know how apply() flattens array items to one level or how apply() takes an array of arguments and treats each element of that array as a single argument.
Let me show a simple example. We have the following object and method:
const showFullName = (arg_1, arg_2) => {
console.log(`arg_1 is ${arg_1}`);
console.log(`arg_2 is ${arg_2}`);
}
let foo = {};
showFullName.apply(foo, ['firstName', 'surname']);

The [] is an empty array. The concat function concatenate two or more arrays: [].concat(arr[0], arr[1], arr[2], arr[3])
The catch here is to know how apply works. The second parameter of apply is an array of parameters. It's like doing this (if you're familiar with the concept of desctructuring):
[].concat(...arr)
You can read more about apply here

Related

How to access the last element of an array using destructuring? [duplicate]

This question already has answers here:
Destructuring to get the last element of an array in es6
(17 answers)
Get first and last elements in array, ES6 way [duplicate]
(1 answer)
Closed 8 months ago.
Suppose I have an array like this: [2, 4, 6, 8, 10].
I want to access the first and last element of this array using destructuring, currently I'm doing this:
const array = [2, 4, 6, 8, 10];
const [first, , , , last] = array;
console.log(first, last);
But this is only works with arrays of length 5 and is not generic enough.
In Python I could do something like this:
array = [2, 4, 6, 8, 10]
first, *mid, last = array
print(first, last)
But in JS this is not possible since rest elements should be the last. So, is there some way to do this in JS or this is not possible?
You can use object destructuring and grab the 0 key (which is the first element) and rename it to first & then using computed property names you can grab the array.length - 1 key (which is the last element) and rename it to last.
const array = [2, 4, 6, 8, 10];
const { 0: first, [array.length - 1]: last } = array;
console.log(first, last);
You can also grab the length via destructuring and then use that to grab the last element.
const array = [2, 4, 6, 8, 10];
const { length, 0: first, [length - 1]: last } = array;
console.log(first, last);
Another simple approach to access the last element would be to use the Array.prototype.at method. This is not related to destructuring but it's worth knowing.
const array = [2, 4, 6, 8, 10];
console.log(array.at(-1));
Not necessarily using destructuring, but still concise in my opinion:
const arr = [1, 2, 3, 4, 5];
const [ first, last ] = [ arr.at(0), arr.at(-1) ];
console.log(first, last);
No, you can't use destructuring like that without convoluted workarounds.
A shorter, more readable alternative is to just pop:
const array = [2, 4, 6, 8, 10];
const [first, ...middle] = array;
const last = middle.pop();
console.log(first, middle, last);
Or, just access them by index:
const array = [2, 4, 6, 8, 10];
const first = array[0];
const last = array[array.length - 1];
console.log(first, last);

How would one add items to the beginning of an array with Lodash?

I've been searching for a while to add items to the beginning of an array with lodash. Unfortunately I can't seem to find anything other than lodash concat (to the end of the array). The docs don't seem to say anything about it either.
I got the following code:
const [collection, setCollection] = useState({
foo: [1, 2, 3]
});
const addToCollection = (key, items) => {
setCollection(prevCollection => ({
...prevCollection,
[key]: _.concat(prevCollection[key] || [], items)
}));
};
But this concats all the items to the end. I don't want to sort them every time because that uses unnessecary processing power, I would much rather just add them to the beginning because the API always pushes the items already sorted
How would I accomplish this:
addToCollection('foo', [4, 5, 6]);
console.log(collection['foo']) // [4, 5, 6, 1, 2, 3];
Instead of what is happening now:
addToCollection('foo', [4, 5, 6]);
console.log(collection['foo']) // [1, 2, 3, 4, 5, 6];
Try swapping the arguments:
_.concat(items, prevCollection[key] || [])
Or vanilla JS is pretty easy too:
Collection.unshift('addMe', var, 'otherString' )
https://www.w3schools.com/jsref/jsref_unshift.asp#:~:text=The%20unshift()%20method%20adds,use%20the%20push()%20method.
I know you asked for lodash but I figured this is a good thing to be aware of too :)
EDIT:
To clarify, this works the same whether you're pushing defined vars, string, arrays, objects or whatever:
let yourArray = [1,2,3];
let pushArray = [1,2,3,4];
let anotherArray = [7,8,9];
yourArray.unshift(pushArray, anotherArray);
will push "pushArray" and "anotherArray" to the begining of "yourArray" so it's values will look like this:
[[1,2,3,4], [7,8,9], 1,2,3]
Happy Coding!

Trying to create copies of an array using spread operator, but some how the array is being mutated

I'm trying to practice with the concept of immutability. I'm using the the spliceTest array as my main reference for creating copies of the array and mutating those. I'm coming to the problem when I declare removeOneItem variable, I somehow can't declare a new spread variable using the same reference of spliceTest.
const removeOneItem = [...spliceTest.splice(0,0), ...spliceTest.splice(1)];
const removeFive = [...spliceTest.splice(0,4), ...spliceTest.splice(5)];
const spreadTest = [...spliceTest];
console.log('removeOneItem:', removeOneItem)
console.log('spreadTest:', spreadTest, spliceTest)
console.log('removeFive:', removeFive)
Results::::::::::::
removeOneItem: [ 2, 3, 4, 5, 6, 7, 8, 9 ]
spreadTest: [] []
removeFive: [ 1 ]
According to MDN:
The splice() method changes the contents of an array by removing or
replacing existing elements and/or adding new elements in place.
This means, that the splice operation changes your array
Immutability of data is a cornerstone of functional programming and in general I'll do what you are trying to do: clone the data and mutate the clone. The following function takes an array and a series of sub-arrays. The sub-arrays consist of [startIndex, quantity]. It clones the original array by the spread operator and splices the clone according to the second parameter (...cutDeep). It will return an object with the original array and the cloned array. If you wrap everything in a function then your scope protects each return. Note on subsequent turns The second clone (secondResult.dissected) is spliced once more and the last log proves the original array is never mutated.
Demo
const data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'];
const dissect = (array, ...cutDeep) => {
let clone = [...array];
for (let [cut, deep] of cutDeep) {
clone.splice(cut, deep);
}
return {
original: array,
dissected: clone
};
}
const firstResult = dissect(data, [2, 3], [5, 2], [9, 1]);
const secondResult = dissect(data, [3, 2], [10, 1]);
console.log(JSON.stringify(firstResult));
console.log(JSON.stringify(secondResult));
console.log(JSON.stringify(dissect(secondResult.dissected, [0, 2], [5, 1])));
console.log(JSON.stringify(data));
The problem is that you use splice when you most likely want to use slice.
splice is used for mutating an array, while slice is used to select a sub-array.
const sliceTest = [1, 2, 3, 4, 5, 6, 7, 8, 9];
// select a sub-array starting from index 1 (dropping 0)
const removeOneItem = sliceTest.slice(1);
// select a sub-array starting from index 5 (dropping 0, 1, 2, 3, and 4)
const removeFive = sliceTest.slice(5);
// spread the full array into a new one
const spreadTest = [...sliceTest];
// array log helpers (leave these out in your code)
const toString = array => "[" + array.join(",") + "]";
const log = (name, ...arrays) => console.log(name, ...arrays.map(toString));
log('removeOneItem:', removeOneItem)
log('spreadTest:', spreadTest, sliceTest)
log('removeFive:', removeFive)
slice already creates a shallow copy of the array, so [...arr.slice(i)] is not needed.

How do I apply array methods to individual array that compose a two dimensional array in javascript?

As a two dimensional array is an array of arrays, I needed to apply array methods .unshift() and .pop() to each individual array in a 2D array of my JavaScript code.
Is there a way to do so? I know an individual member can be accessed by looping along a[i][j], but how do I obtain the individual array for applying methods to it?
Example: I have an array:
var a = [
[1,2,3]
[4,5,6]
[7,8,9]
]
Now in the first row I want to remove 3 from last and add 3 to the beginning giving me [3,1,2]. And do the same for all rows.
You can iterate over your array using .forEach(), and then for each element in your array (ie: each inner array), .pop() the last element from the end of your array, and then use .unshift(element) to prepend the element you just popped off you're array:
const a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
a.forEach(innerArray => {
const last = innerArray.pop();
innerArray.unshift(last);
});
console.log(a);
The above can be implemented using a regular for loop if you find that easier to understand:
const a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
for(let i = 0; i < a.length; i++) {
const innerArray = a[i];
const last = innerArray.pop();
innerArray.unshift(last);
}
console.log(a);
You can also do this by using .map(), which will produce a new array, leaving your original array a untouched:
const a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const a_new = a.map(inner => [inner.pop(), ...inner]);
console.log(a_new);
Map it. Functional programming is cool!
// to delete the first and last element of the inner array - `unshift` + `pop`
const result = someArray.map(innerArray => innerArray.slice(1, -1));

How does using specifically "[]" as a parameter work?

I was doing some javascript exercises online (codewars.com). One problem asked the user to take an array of array objects and remove one level from the entirety of the array.
[] /* becomes */ []
[[1, 2, 3], ["a", "b", "c"], [1, 2, 3]] /* becomes */ [1, 2, 3, "a", "b", "c", 1, 2, 3]
[[3, 4, 5], [[9, 9, 9]], ["a,b,c"]] /* becomes */ [3, 4, 5, [9, 9, 9], "a,b,c"]
I ended up learning about the concat method, but the most popular solution used this statement...
function (arr){
return [].concat.apply([],arr);
}
Can someone please explain the usage of [] here? I can't understand how this produces the correct results (and it doesn't give explanation on the page). I know that there are plenty of other times in which empty brackets are used as parameters and labeling arrays so understanding the usage here may help me be able to use it myself in the future.
Lets split this across multiple lines so it is easier to describe. The description of line D specifically is what answers your question
[] // A
.concat // B
.apply( // C
[], // D
arr // E
);
A Is an Array, but here it is just being using as a shortcut to Array.prototype so we can access..
B The concat method from Array.prototype
C which we then invoke (using apply) with a
D this argument of a new Array, to be the base Object and
E a list of arguments, which was our previous arr
So, you could re-write this using Array.prototype and call as
var new_base_arr = [];
Array.prototype.concat.call(
new_base_arr,
arr[0],
arr[1],
...
arr[n]
);
Which might look more familiar to you written as
new_base_arr.concat(arr[0], arr[1], ..., arr[n]);
The problem being solved here is invoking a function with an undetermined number of arguments.

Categories

Resources