最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How do you use a reduce function to find the intersectionunion between a set of arrays in javascript functional programming? - S

programmeradmin2浏览0评论

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
Add a ment  | 

7 Answers 7

Reset to default 4

I 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.

  1. 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

  2. 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]);
}

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论