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

arrays - How to create a partition function in javascript. using the following guidelines - Stack Overflow

programmeradmin0浏览0评论

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);
}

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);
}
Share Improve this question edited Jan 25, 2016 at 8:31 Mr Lister 46.6k15 gold badges113 silver badges155 bronze badges asked Jan 19, 2016 at 22:15 JesusHBruhnkeJesusHBruhnke 331 silver badge5 bronze badges 8
  • there is a formatting iussue in your request that makes it difficult to read it. – Marco Altieri Commented Jan 19, 2016 at 22:17
  • Looking at it now, I know my original thought was to filter the strings into one array and the numbers into another array, yet when I test it, it returns just a number. So somewhere my logic is off. More than likely it is something very simple. – JesusHBruhnke Commented Jan 19, 2016 at 22:18
  • 1 can you show us a sample input+desired output? – dandavis Commented Jan 19, 2016 at 22:20
  • 1 try return allValues.push(matches, misMatches), allValues; – dandavis Commented Jan 19, 2016 at 22:29
  • 1 In your question text, you say returned something truthy, but in your sample code you are paring the returned value to "string"--which is correct? – user663031 Commented Jan 20, 2016 at 3:15
 |  Show 3 more ments

4 Answers 4

Reset to default 5

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];
}

You're correct about calling the filter method on separate occasions. One filter call would obtain the truthy values; the other would obtain the falsy values:

_.partition = function(collection, testFunc) {
  var matches = collection.filter(function(elem) {
    return test(elem) === 'string';
  });

  var misMatches = collection.filter(function(elem) {
    return test(elem) !== 'string';
  });

  return [matches, misMatches];
}

You are close, but there are a couple issues I see:

  1. You are returning the result of allValues.push which is not allValues itself, but rather the new length of the array.
  2. You are using _.filter to iterate over array elements and sort them into two arrays. This is strange, since it's not the intended use of _.filter.

If you want a quick and readable solution using _.filter, this will work:

_.mixin({
  partition: function(collection, test) {
    return [
      _.filter(collection, test),  // items which satisfy condition
      _.filter(collection, _.negate(test))  // items which don't
    ];
  }
});

A more efficient solution which makes only one pass over the collection is below (this is almost what you already have):

_.mixin({
  partition: function(collection, test) {
    var matches = [], misMatches = [], value;

    // can replace this loop with _.each
    for (var i = 0, len = collection.length; i < len; ++i) {
      value = collection[i];

      // push the value into the appropriate array
      if (test(value, i, collection)) {
        matches.push(value);
      } else {
        misMatches.push(value);
      }
    }

    return [matches, misMatches];
  }
});

Usage examples (and Plunker):

function isOdd(x) {
  return x % 2;
}

// _.mixin allows you to do either one of these
_.partition([1, 2, 3, 4, 5, 6], isOdd);  // result: [[1, 3, 5], [2, 4, 6]]
_([1, 2, 3, 4, 5, 6]).partition(isOdd);  // result: [[1, 3, 5], [2, 4, 6]]

// this is a use case you brought up in the ments
_.partition([1, "a", 2, "b", 3, "c"], _.isString);  // result: [["a", "b", "c"], [1, 2, 3]]

This is generally known as partition ing in functional languages. You suply an array (xs) and a predicate function (p) to a reduceing function with initial value [[],[]].

var partition = (xs,p) => xs.reduce( (r,e) => ( p(e) ? r[0].push(e)
                                                     : r[1].push(e)
                                              , r
                                              )
                                   , [[],[]]
                                   );

Such that;

> partition([1,2,3,4,5,6,7,8,9,0], x => x < 5)
> [[1, 2, 3, 4, 0],[5, 6, 7, 8, 9]]
发布评论

评论列表(0)

  1. 暂无评论