I have re-created foreach + map + reduce functions in js:
function forEach(array, callback) {
for (var i=0;i<array.length;i++) {
callback(array[i])
}
}
function mapWith(array, callback) {
var output= [];
forEach(array , function(el){
return output.push(callback(el))
});
return output;
}
function reduce(array, callback, initialValue) {
mapWith(array, function(el){
return initialValue = callback(initialValue, el);
})
return initialValue;
}
Now how would i use reduce to find the intersection between a set of arrays?
function intersection(arrays) {
}
// console.log(intersection([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]));
// should log: [15, 5]
Also, how would I pare input arrays and return a new array that contains all elements. If there are duplicate elements, only added once to the new array. The order of the elements starting from the first element of the first input array is preserved.
function union() {
}
// console.log(union([5, 10, 15], [15, 88, 1, 5, 7], [100, 15, 10, 1, 5]));
// should log: [5, 10, 15, 88, 1, 7, 100]
I have re-created foreach + map + reduce functions in js:
function forEach(array, callback) {
for (var i=0;i<array.length;i++) {
callback(array[i])
}
}
function mapWith(array, callback) {
var output= [];
forEach(array , function(el){
return output.push(callback(el))
});
return output;
}
function reduce(array, callback, initialValue) {
mapWith(array, function(el){
return initialValue = callback(initialValue, el);
})
return initialValue;
}
Now how would i use reduce to find the intersection between a set of arrays?
function intersection(arrays) {
}
// console.log(intersection([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]));
// should log: [15, 5]
Also, how would I pare input arrays and return a new array that contains all elements. If there are duplicate elements, only added once to the new array. The order of the elements starting from the first element of the first input array is preserved.
function union() {
}
// console.log(union([5, 10, 15], [15, 88, 1, 5, 7], [100, 15, 10, 1, 5]));
// should log: [5, 10, 15, 88, 1, 7, 100]
Share
Improve this question
edited Dec 16, 2016 at 5:07
user663031
asked Dec 16, 2016 at 4:01
Jull WeberJull Weber
511 silver badge4 bronze badges
1
- FWIW, above sourced from: csbin.io/callbacks – Sahil Tandon Commented Feb 7, 2018 at 1:40
7 Answers
Reset to default 4I think Will Sentance will be OK with this too :)
const union = (arrays) => { return arrays.reduce((a, b) => Array.from(new Set(a.concat(b)))) };
const intersection = (arrays) => { return arrays.reduce((a, b) => a.filter(ele => b.includes(ele))) };
Now how would i use reduce to find the intersection between a set of arrays?
An implementation using reduce would be to take each array in turn and eliminate (filter out) elements from the result if they don't exist in that array.
function intersection(arrays) {
return reduce(arrays, (result, array) =>
filter(result, e => array.includes(e)));
};
This assumes you have written your own filter
:
function filter(array, callback) {
var output= [];
forEach(array , function(el) {
if (callback(el)) output.push(el);
});
return output;
}
Another idea would be to start off by concatenating all the arrays:
function concat(arrays) { return [].concat(...arrays); }
And then filter to include only elements which occur in all arrays:
function intersection(arrays) {
return concat(arrays).filter(e => arrays.every(a => a.includes(e));
}
If you don't want to use the built-in Array#every
, and continue down the path of writing your own:
function every(array, callback) {
for (var i = 0; i < array.length; i++)
if (!callback(array[i])) return false;
return true;
}
Using that and your own filter
, intersect
then bees:
function intersection(arrays) {
return filter(concat(arrays), e => every(arrays, a => a.includes(e)));
}
Array#includes
is ES7 and might not be supported in your favorite browser. In that case, use a.indexOf(e) !== -1
instead, or write your own.
Some people might like to write that more "semantically" as:
function intersection(arrays) {
const inAll = e => every(arrays, a => a.includes(e));
return filter(concat(arrays), inAll);
}
Also, how would I pare input arrays and return a new array that contains all elements. If there are duplicate elements, only added once to the new array. The order of the elements starting from the first element of the first input array is preserved.
I don't know what you mean by "pare". Anyway, to do what you apparently want, concatenate them and apply some uniq
-like utility:
function union(arrays) {
return uniq(concat(arrays));
}
There are many implementations of uniq
out there. Here's a real simple one:
function uniq(arr) {
return arr.filter((elt, i) => arr.indexOf(elt) === i);
}
Using custom reduce and foreach
function forEach(array, callback) {
for(i = 0; i < array.length; i++){
callback(array[i])
}
}
function reduce(array, callback, initialValue) {
for(let i of array){
initialValue = callback(initialValue, i)
}
return initialValue
}
function intersection(init, ...arrays) {
return reduce(arrays, (current, next) => {
const filtered = []
forEach(next, (el) => {
if(current.includes(el)) filtered.push(el)
})
return filtered
}, init)
}
Alternative using in-built reduce and forEach
function intersection(...arrays) {
return arrays.reduce((current, next) => {
const filtered = []
next.forEach((el) => {
if(current.includes(el)) filtered.push(el)
})
return filtered
})
}
Refer to specification for algo definition as to how reduce functions without a specified initialValue.
https://tc39.es/ecma262/#sec-array.prototype.reduce
Without a defined initial array, I didn't expect it to work.
Ensure you test your implementation with multiple test cases. My initial solution was producing the correct answers but was not even looking at the last array. I had an error in my reduce.
Compare the firs and the second array and return a new array with the mon elements, continue paring the returned array with the rest of the arrays one by one and every time return a new array with the mon elements
how to pare 2 arrays for mon elements? use the filter method..
function intersection(...arrays) {
return arrays.reduce((resultArray, currentArray) => {
return resultArray.filter(el => currentArray.includes(el))
})
}
console.log(intersection([5, 10, 15, 20], [15, 88, 17, 5, 7], [1, 10, 15, 5, 20]));
// should log: [5, 15]
try this
const a = [1,2,3,4,5,6];
const b = [1,2,3,9,45,15];
const c = [13,2,5,3,10];
function intersection (...lists){
const all = [...new Set([].concat(...lists))]; //to remove duplicates
return all.reduce( ( accumulator, currentValue ) => {
if(lists.every( list => list.includes(currentValue) )){
return [...accumulator, currentValue];
}else{
return [...accumulator]
}
}, [])
}
console.log( 'intersection', intersection(a,b,c) ); //returns [2,3]
you can try this
// spread operator returns an array of arrays
function intersection(...arrays) {
// setting output to array
const output = []
// initial value is of accumulator is an object
reduce(arrays,function(acc,currentArray){
// for each item check if item exist in accumulator(object)
forEach(currentArray,function(item){
// if it does
if(item in acc) {
// increment its value
acc[item]++
}else {
// else make it a property of accumulator(object) and set value to 1
acc[item] = 1;
}
// if accumulator property of current item is === length of arrays i.e appears the same amount of times as total amount of arrays in arrays
if(acc[item] === arrays.length){
// push item onto output
output.push(item)
}
})
// returns accumulator into reduce function
return acc
},{})
//returns output as the intersection
return output
}
The difference between intersection and union would be in the last if statement instead of checking against the total amount of arrays in arrays we would check if its value is equals to 1 (===1) now to the code:
// spread operator returns an array of arrays
function union(...arrays) {
// setting output to array
const output = []
// initial value is of accumulator is an object
reduce(arrays,function(acc,currentArray){
// for each item check if item exist in accumulator(object)
forEach(currentArray,function(item){
// if it does
if(item in acc) {
// increment its value
acc[item]++
}else {
// else make it a property of accumulator(object) and set value to 1
acc[item] = 1;
}
// if accumulator property of current item is === length of arrays i.e appears once
if(acc[item] === 1){
// push item onto output
output.push(item)
}
})
// returns accumulator into reduce function
return acc
},{})
//returns output as the union
return output
}
hope someone finds this helpful
If you want to solve this problem without using built-in functions like filter
function intersection(arrays) {
return reduce(arrays, function(arrA, arrB) {
forEach(arrA, function(item) {
if (arrB.indexOf(item) == -1) {
arrA.splice(arrA.indexOf(item), 1);
}
});
return arrA;
}, arrays[0]);
}
function union(arrays) {
return reduce(arrays, function(arrA, arrB) {
forEach(arrB, function(item) {
if (arrA.indexOf(item) == -1) {
arrA.push(item);
}
});
return arrA;
}, arrays[0]);
}