How can I use reduce to calculate the intersection of multiple arrays? - javascript

Example:
myArray = [[1,2,3,4],
[2,3,4,5],
[3,4,5,6]
];
Expected output:
newArray = [3,4]
How do I generate a new array with the values present in all 3 arrays?

While reducing, return an intersection of the accumulator with the current sub-array being iterated over:
const myArray = [[1,2,3,4], [2,3,4,5], [3,4,5,6]];
const intersection = myArray.reduce((a, arr) => (
a.filter(num => arr.includes(num))
));
console.log(intersection);

You can use .filter() to extract the matching values:
let myArray = [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]];
let intersect = ([f, ...r]) => f.filter(v => r.every(a => a.includes(v)));
console.log(intersect(myArray));

Related

How to filter array by array using javascript with duplicate key

I have 2 array and i will filtered but key duplicate.
const arr1 = [1, 2, 3, 3, 3, 4];
const arr2 = [1, 3];
function filteredArray(arr1, arr2) {...}
const newArr = filteredArray(arr1, arr2);
console.log(newArr);
// result: [2, 3, 3, 4];
You can check the below implementation. We should not modify the original data as well, that's why I've cloned your array for the array modification instead of changing items on the original one.
const arr1 = [1, 2, 3, 3, 3, 4];
const arr2 = [1, 3];
function filteredArray(arr1, arr2) {
const newArr1 = [...arr1] //clone the array to keep the original array data
const set2 = new Set(arr2)
for(let i = 0; i < newArr1.length; i++) {
if(set2.has(newArr1[i])) {
set2.delete(newArr1[i])
newArr1.splice(i,1)
}
}
return newArr1
}
const newArr = filteredArray(arr1, arr2);
console.log(newArr);
Use set and filter
function filteredArray(arr1, arr2) {
const set = new Set(arr2);
return arr1.filter(item => !set.delete(item));
}
const arr1 = [1, 2, 3, 3, 3, 4];
const arr2 = [1, 3];
console.log(filteredArray(arr1, arr2));

How to triplicate specific items in an array for javascript?

Is there any way to only triplicate certain elements in an array? I want to triplicate the "3" in the array only.
For instance:
const deck = [1, 3, 9, 3, 7];
should become [1, 3, 3, 3, 9, 3, 3, 3, 7]
I have tried the method below, deck is the random array:
var i;
for (let i=0;i<deck.length;i++){
if (deck[i]==3){
return deck.flatMap(x=>[x,x,x]);
}else return deck[i];
}
}
You could write a function that uses flatMap() to map over the array and triplicate the specific values.
const deck = [1, 3, 9, 3, 7];
const triplicate = (number, arr) => {
return arr.flatMap(x => x === number ? [x, x, x]: x);
}
console.log(triplicate(3, deck));
Using Array#flatMap:
const triplicate = (arr = [], number) =>
arr.flatMap(n => n === number ? [n, n, n] : n);
console.log( triplicate([1, 3, 9, 3, 7], 3) );

Deleting arrays of same elements in 2 dimensional array in Javascript

I am wondering how you would go about deleting arrays that contain the same elements in a 2 dimensional array.
For example:
let 2dArr = [ [1, 2, 3],
[3, 2, 1],
[2, 4, 5],
[4, 5, 2],
[4, 3, 1] ];
This array would delete the second and fourth elements, returning the 2d array:
returnedArr = [ [1, 2, 3],
[2, 4, 5],
[4, 3, 1] ];
How exactly could this be done, preserving the 2d array? I could only think to loop through elements, comparing elements via a sort, and deleting them as you go along, but this would result in an indexing error if an element is deleted.
1) You can easily achieve the result using reduce and Set as:
let twodArr = [
[1, 2, 3],
[3, 2, 1],
[2, 4, 5],
[4, 5, 2],
[4, 3, 1],
];
const set = new Set();
const result = twodArr.reduce((acc, curr) => {
const key = [...curr].sort((a, b) => a - b).join();
if (!set.has(key)) {
set.add(key);
acc.push(curr);
}
return acc;
}, []);
console.log(result);
2) You can also use filter as:
let twodArr = [
[1, 2, 3],
[3, 2, 1],
[2, 4, 5],
[4, 5, 2],
[4, 3, 1],
];
const set = new Set();
const result = twodArr.filter((curr) => {
const key = [...curr].sort((a, b) => a - b).join();
return !set.has(key) ? (set.add(key), true) : false;
});
console.log(result);
const seen = []
const res = array.filter((item) => {
let key = item.sort().join()
if(!seen.includes(key)){
seen.push(key)
return item
}
})
console.log(res)
You can use hash map
let arr = [ [1, 2, 3], [3, 2, 1],[2, 4, 5],[4, 5, 2],[4, 3, 1] ];
let obj = {}
let final = []
for(let i=0; i<arr.length; i++){
// create a key
let sorted = [...arr[i]].sort((a,b)=> a- b).join`,`
// check if this is not present in our hash map
// add value to final out and update hash map accordingly
if(!obj[sorted]){
obj[sorted] = true
final.push(arr[i])
}
}
console.log(final)
Using Array.prototype.filter() and a Set as thisArg
let arr = [ [1, 2, 3],
[3, 2, 1],
[2, 4, 5],
[4, 5, 2],
[4, 3, 1] ];
let res = arr.filter(function(e){
const sorted = [...e].sort((a,b) => a-b).join('|');
return this.has(sorted) ? false : this.add(sorted)
},new Set)
console.log(res)

More efficient, but readable alternative for this block of JavaScript code

Let's say I got 3 arrays, of which one is based on the other array, but I need to combine them into one.. I'm using forEach loops here to push items to the array but I feel like that's inefficient.
const arr1 = [1, 2, 3];
const arr2 = ["a", "b"];
const arr3 = ["foo", "bar", "baz"];
const obj = {
"1_a": [1, 2],
"1_b": [1, 2, 3],
"2_a": [1],
"2_b": [1, 2],
"3_a": [],
"3_b": [1, 2, 3]
};
// push all the items to the temporary array - with forEach loops,
// I feel like this logic can be made more readable and efficient
let tempArr = [];
arr1.forEach(i =>
arr2.forEach(j =>
tempArr.push(`${i}_${j}`)
)
);
arr3.forEach(i => tempArr.push(i));
// loop over the temporary array to get the final result (logged below)
const arr = tempArr.map(key => {
if (obj[key] !== undefined && obj[key].length > 1) return `update_${key}`;
else return key;
});
// result
console.log(arr); // [ "update_1_a", "update_1_b", "2_a", "update_2_b", "3_a", "update_3_b" ]
I feel like I'm doing something wrong here with all the forEach pushes, I feel like there should be something like a nested map function..? Please help me out here..
I would like the following to happen:
The values of arr2, are based on the loop of arr1 (see example), these get combined with an underscore, pseudo: arr1Item_arr2Item, and this item gets pushed to the array.
The values of arr3, just get looped and pushed
The merged array gets looped, and in case the value of that item is in the object, and the array of that key is longer than 1, return update_<arrItem>, else just return <arrItem>
Not sure if it's any better, but it is a reduce and a map:
const arr1 = [1, 2, 3];
const arr2 = ["a", "b"];
const arr3 = ["foo", "bar", "baz"];
const obj = {
"1_a": [1, 2],
"1_b": [1, 2, 3],
"2_a": [1],
"2_b": [1, 2],
"3_a": [],
"3_b": [1, 2, 3],
};
const result = arr1.reduce(
(a, c) =>
(a.concat(
arr2.map((y) => {
const key = `${c}_${y}`;
return obj[key] !== undefined && obj[key].length > 1
? `update_${key}`
: key;
})
)),
arr3
);
console.log(result);
you can try:
const arr1 = [1, 2, 3];
const arr2 = ['a', 'b'];
const obj = {
'1_a': [1, 2],
'1_b': [1, 2, 3],
'2_a': [1],
'2_b': [1, 2],
'3_a': [],
'3_b': [1, 2, 3]
};
const result = arr1.reduce((acc, a1) =>
[...acc, ...arr2.map(a2 => {
const keyCombined = `${a1}_${a2}`;
return obj[keyCombined].length > 1
? `update_${keyCombined}`
: `${keyCombined}`;
})], []);
console.log(result);
Another approach using flatMap:
const arr1 = [1, 2, 3];
const arr2 = ["a", "b"];
const arr3 = ["foo", "bar", "baz"];
const obj = {
"1_a": [1, 2],
"1_b": [1, 2, 3],
"2_a": [1],
"2_b": [1, 2],
"3_a": [],
"3_b": [1, 2, 3]
};
const result = [
...arr3,
...arr1
.flatMap(a => arr2
.map(b => {
const key = `${a}_${b}`;
return obj[key].length > 1
? `update_${key}`
: key;
}))
]
console.log(result)

Create a sorted array by mistake using .map()

I tried to make something that works as Set() using a couple tools that I learned. It worked, but I noticed a bug: it sorted my array! Can explain me someone why, please?
Here's my code:
function uniteUnique(...arr) {
let array = arr.flat()
let newArr = [];
console.log(array) // [ 1, 3, 2, 5, 2, 1, 4, 2, 1 ]
let myMap = array
.map(elem => {
if (!newArr.includes(elem))
return newArr.push(elem)
})
.filter(Boolean)
console.log(myMap) // [ 1, 2, 3, 4, 5 ]
}
uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
I know that for you might be too simple, but I ask so I can understand what is happening here.
console.log(myMap) // [ 1, 2, 3, 4, 5 ]
The result of your log is the number of pushed elements but accidentally, you thought they are sorted.
Also, if you return the mapped list you will end up with an array that contains an integer and boolean values. Instead of this, you need to return newArr.
Your code will be like this :
function uniteUnique(...arr) {
let flattedArray = arr.flat()
let set = [];
flattedArray.forEach(elem => !set.includes(elem) && set.push(elem))
return set
}
const set = uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
console.log(set)
in your code MyMap holds your newArr length as array.push returns the length of your array
so every time it returns the count:
for example if you tried to run this code
let newArr = []
console.log(newArr.push(20)) // the output is 1
and that's what your myMap holds => the length of your newArr
so if you want the filtered array you should use newArr
let array = [ 1, 3, 2, 5, 2, 1, 4, 2, 1 ]
let newArr = [];
let myMap = array.map(elem => {
if (!newArr.includes(elem))
return newArr.push(elem)
}).filter(Boolean)
console.log(newArr) //[1, 3, 2, 5, 4]

Categories