Search code examples
javascriptarraysunderscore.js

How to create a partition function in javascript. using the following guidelines


I've been trying to create a generic partition function that returns an array of arrays. the function should be made under the following guidelines:
Arguments:

  1. An array
  2. A function

Objectives:

  1. Call <function> for each element in <array> passing it the arguments:

    element, key, <array>
    
  2. Return an array that is made up of 2 sub arrays:

     0. An array that contains all the values for which <function> returned something truthy
     1. An array that contains all the values for which <function> returned something falsy

Here is what I have so far. I get the return of two. I feel like maybe I just have to do the filter function on two separate occasions, but I'm not sure how to put it together. Thoughts and suggestions are highly appreciated.

_.partition = function (collection, test){
    var allValues = [];
    var matches = [];
    var misMatches = [];
    _.filter(collection.value, function(value, key, collection){
      if (test(value[key], key, collection) === "string"){
        matches.push(value[key]);
      }else{
        misMatches.push(value[key]);
      }
    });
  return allValues.push(matches, misMatches);
}

Solution

  • Here is a version which uses reduce:

    function partition(arr, filter) {
      return arr.reduce(
        (r, e, i, a) => {
          r[filter(e, i, a) ? 0 : 1].push(e);
          return r;
        }, [[], []]);
    }
    

    Here's an alternative version which uses Array#filter to find the matches, and builds an array of non-matches as it goes along:

    function partition(arr, filter) {
      var fail = [];
    
      var pass = arr.filter((e, i, a) => {
        if (filter(e, i, a)) return true;
        fail.push(e);
      });
    
      return [pass, fail];
    }
    

    And a typed TypeScript variant:

    function partition<T>(arr: T[], filter: (el: T, i: number, a: T[]) => boolean) {
      const fail: T[] = [];
    
      const pass = arr.filter((e, i, a) => {
        if (filter(e, i, a)) return true;
        fail.push(e);
      });
    
      return [pass, fail];
    }