Lodash union won't work with the spread operator - javascript

I am using lodash and it's union function. But when I use a spread operator within union I am no longer getting the normal, expected result. What am I doing wrong and why won't lodash work with the spread operator? Thanks!
x = [1, 2, 3, 4]
y = [3, 5]
normalResult = _.union(x, y)
unexpectedResult = _.union(...x, y)
// normalResult = [1, 2, 3, 4, 5]
// unexpectedResult = [3, 5]

_.union expects each argument to be an array. When you use ...x you're spreading the array into separate arguments, which is not what it wants.
The spread operator would be useful if you had a 2-dimensional array and you wanted to merge each of the contained arrays with _.union, e.g.
x = [1, 2, 3, 4]
y = [3, 5]
a = [x, y];
result = _.union(...a);

Related

Merge two arrays at a specific index [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Let's say I have an array called array1:
var array1 = [1, 2, 5];
And I have another called array2:
var array2 = [3, 4];
I want to output the result [1, 2, 3, 4, 5] by inserting array2 at index number 2 of array1.
How can achieve this in JavaScript?
EDIT:
More things to note:
Array mutation in place does not matter, either way would be fine.
The order of the array elements does not matter, the task at hand is to merge two arrays at a specified index.
I've come up with one possible implementation:
// merge 'b' with 'a' at index 'i'
function merge(a, b, i=0) {
return a.slice(0, i).concat(b, a.slice(i));
}
var result = merge([1, 2, 5], [3, 4], 2);
console.log(result);
You might try spreading b's elements into splice, which adds a series of arguments at index i (the optional argument removal is ignored with 0). a will be modified in place.
const mergeInPlace = (a, b, i=0) => a.splice(i, 0, ...b);
const a = [1, 2, 5];
const b = [3, 4];
mergeInPlace(a, b, 2);
console.log(a);
If you want to avoid mutation, spread and slice is probably easiest:
const merge = (a, b, i=0) => [...a.slice(0, i), ...b, ...a.slice(i)];
const a = [1, 2, 5];
const b = [3, 4];
console.log(merge(a, b, 2));
If you don't want to mutate the original array you can spread slices out into a new array:
var array1 = [1, 2, 5];
var array2 = [3, 4];
function merge(a1, a2, i){
return [...a1.slice(0,i), ...a2, ...a1.slice(i)]
}
console.log(merge(array1, array2, 2))
// negative indexing too
console.log(merge(array1, array2, -2))
If the goal is just to order them:
array1.concat(array2).sort();
var array1 = [1, 2, 5],
array2 = [3, 4];
let r = array1.concat(array2).sort();
console.log(r);
If the goal is to insert at a certain index:
array1.splice(2,0,array2);
array1.flat();
var array1 = [1, 2, 5],
array2 = [3, 4];
array1.splice(2,0,array2);
let r = array1.flat();
console.log(r);
As an alternative to that you can use a functional approach. I offer this because I find .splice to be an ugly method that mutates the array,is too closely named to slice, and doesn't even return the array you're probably looking for.
let combineAt = (n, a, b) =>
a.reduce((ac, cv, ci) =>
(n === ci) ?
(ac.push(b, cv), ac.flat()) :
(ac.push(cv), ac), []);
combineAt(2,array1,array2);
var array1 = [1, 2, 5],
array2 = [3, 4];
let combineAt = (n, a, b) => a.reduce((ac, cv, ci) => (n === ci) ? (ac.push(b, cv), ac.flat()) : (ac.push(cv), ac), []);
let r = combineAt(2, array1, array2);
console.log(r);

Array destructuring and spread operator

It's not 100% clear to me how this piece of code works:
var a = [1, 2, 3];
[x, y, ...a ] = [0, ...a, 4];
// OUTPUT:  [0, 1, 2, 3, 4]
I'm deconstructing the array a using the ... operator.
I am expecting that in second line a bunch of assignments will take place.
The x will be assigned to 0, y will be assigned to ...a (which passes the elements in the array a as individual values).
It's not clear to me, though, how the ...a get assigned to 4. In fact, JS throws an exception when doing:
...a = 4;
// Uncaught SyntaxError: Rest parameter may not have a default initializer
Why does this code output the modified array with the end 4, instead of throwing an exception? How does this work exactly?
It is executed like following
var a = [1, 2, 3];
[x, y, ...a ] = [0, ...a, 4];
[x, y, ...a ] = [0, 1, 2, 3, 4];
which means first value in RHS array is assigned to x, second value in RHS array is assigned to y and the remaining values are assigned to a.
Hence, value of x is 0, y is 1 and a is [2, 3, 4]
It's not clear to me, though, how the ...a get assigned to 4.
It's not.
Lets split things up a little:
On the right hand side of the assignment you are using an array literal with a spread element. The value of a is "flattened" into the new array.
Thus, [0, ...a, 4] is is equivalent to [0].concat(a, [4]). The result is a new array.
var a = [1, 2, 3];
console.log('spread element', [0, ...a, 4]);
console.log('concat', [0].concat(a, [4]));
On the left hand side you are using array destructuring with a rest element. [x, y, ...a ] means
assign the first value of the iterable to x
assign the second value of the iterable to y
assign the remaining values of the iterable as an array to a
These two are equivalent:
var a = [1,2,3,4];
var [x, y, ...z] = a;
console.log('destructuring', x, y, z);
var x = a[0];
var y = a[1];
var z = a.slice(2);
console.log('manual + slice', x, y, z);
Of course combining these two is perfectly fine. In an assignment, the left hand side doesn't care what how the right hand side is computed and vice versa.
What's confusing about your example is that you are using a again in the destructuring assignment, but that's the same as overriding the value of a with a new value. However the end result is
[0, ...a, 4] results in [0,1,2,3,4] therefor
x has value 0
y has value 1
a has value [2,3,4]
In fact, JS throws an exception when doing: ...a = 4;
The error message you are getting is strange. It should really be just a syntax error.
... by itself doesn't mean anything. It's not an operator, it's a punctuator (like ; or ,) that has a different meaning depending on the context it is used (and allowed).
See also What is SpreadElement in ECMAScript documentation? Is it the same as Spread operator at MDN?
...a is either equal to .slice(start, end) (left, destructuring) or to .concat(a) (right, spreading):
[0, ...a, 4]
is equal to:
[0].concat(a).concat([4]) // [0,1,2,3,4]
Whereas:
[x, y, ...a] = array
Is equal to:
x = array[0];
y = array[1];
a = array.slice(2);
In the first example, spread ie ... in LHS acts as gatherer whereas on the RHS it acts as spread/rest. IE you are assigning value to variable a when it is on LHS.
var a = [1, 2, 3];
[x, y, ...a ] = [0, ...a, 4];
console.log(a)
Let's go step by step:
Let's start with RHS. Doing [0, ...a, 4] will generate [0, 1, 2, 3, 4]. See for yourself:
var a = [1, 2, 3];
console.log([0, ...a, 4]);
Now, the LHS is the side where assignment is taking place. On RHS, imagine any variable with spread operator as an array ready to be assigned new values.
So, we are trying to assign [0, 1, 2, 3, 4] to a variable x, then to y and the rest to array a (in that order). So, array a will have whatever will be left after first two assignments (ie 2, 3, 4).
var a = [1, 2, 3];
// a will get overwritten
[x, y, ...a ] = [0, 1, 2, 3, 4];
// same as [x, y, ...a ] = [0, ...a, 4];
console.log(a);
Finally, coming to your last question: "It's not clear to me, though, how the ...a get assigned to 4? "
Answer: It is not. But if you do something like [...a] = [4], it will result in an array named a containing [4].
You can read more about spread syntax here (MDN) and here (YDKJS).

How can I insert array in the middle of another array in es6?

I have two arrays:
let a = [1, 3, 5];
let b = [2, 4];
I need to put second array into first one after second element, so this is result:
[1, 3, 2, 4, 5]
What is the best way to insert second array into first in es6?
It can be easily solved using concat operation, but I am looking for nice way of doing it in es6.
If you want to insert the second array at specific index, you can use splice function and spread operator.
var a = [1, 3, 5];
var b = [2, 4, 6];
a.splice(2, 0, ...b);
console.log(a); // [1, 3, 2, 4, 6, 5]
Use Array#splice method with spread syntax.
a.splice(2, 0, ...b)
let a = [1, 2, 5];
let b = [3, 4];
a.splice(2, 0, ...b);
console.log(a);
I think this is the answer you're looking for:
function frankenSplice(arr1, arr2, n) {
let arr3 = [...arr2];
arr3.splice(n, 0, ...arr1);
return arr3;
}

Is there a more concise way to remove an entry from an array with lodash?

Below are several stabs at removing 3 from the array [8,2,3,4] using lodash. The elegant syntax for removing an object from an array of objects makes me wonder if I just haven't figured out the right approach here.
> _.remove([8,2,3,4], 3)
[]
> x = [8,2,3,4]
[8, 2, 3, 4]
> _.remove(x, 3)
[]
> x
[8, 2, 3, 4]
> _.remove(x, {3: true})
[]
> x
[8, 2, 3, 4]
> _.remove(x, [3])
[]
> x
[8, 2, 3, 4]
> _.remove(x, function(val) { return val === 3; });
[3]
> x
[8, 2, 4]
Is there another way to remove a matching element from an array that would be similar to _.remove(arrayOfObjs, {id:3})
Yes, but not using remove. You can instead use pull to remove values from an array:
Removes all provided values from array using SameValueZero for equality comparisons.
// pull modifies its argument:
x = [8, 2, 3, 4]
_.pull(x, 3)
x // => [8, 2, 4]
// pull also returns the modified array:
y = _.pull([1, 2, 3, 4, 5], 2, 3) // => [1, 4, 5]

remove common elements of two arrays in jquery

I want to remove common elements of two arrays in jquery.
I have two arrays:
A = [0,1,2,3]
B = [2,3]
and result should be [0, 1].
Please help
You can filter array A by checking its elements position in array B:
C = A.filter(function(val) {
return B.indexOf(val) == -1;
});
Demo
ES6 version of Milind Anantwar's answer. May require Babel.
const A = [1, 2, 3, 4];
const B = [2, 4];
const C = A.filter(a => !B.includes(a));
console.log(C) // returns [1, 3]
Use the Set type from ES6. Then the spread operator to build an array from the Set. A Set type can only hold unique items.
const A = [1, 2, 3, 4];
const B = [2, 4];
const C = [...new Set(A,B)];
console.log(C);
(4) [1, 2, 3, 4]
Checkout the library underscore.js.
Say you have two arrays,
var a = [0,1,2,3];
var b = [2, 3];
First find the union.
var all = _.union(a, b);
Then find the intersection.
var common = _.intersection(a, b);
The final answer should be the difference between the union, and the intersection.
var answer = _.difference(all, common)

Categories

Resources