Dividing an array by filter function

后端 未结 12 943
抹茶落季
抹茶落季 2020-12-01 11:24

I have a Javascript array that I would like to split into two based on whether a function called on each element returns true or false. Essentially

相关标签:
12条回答
  • 2020-12-01 12:04

    Easy to read one.

    const partition = (arr, condition) => {
        const trues = arr.filter(el => condition(el));
        const falses = arr.filter(el => !condition(el));
        return [trues, falses];
    };
    
    // sample usage
    const nums = [1,2,3,4,5,6,7]
    const [evens, odds] = partition(nums, (el) => el%2 == 0)
    
    0 讨论(0)
  • 2020-12-01 12:05

    I came up with this little guy. It uses for each and all that like you described, but it looks clean and succinct in my opinion.

    //Partition function
    function partition(array, filter) {
      let pass = [], fail = [];
      array.forEach((e, idx, arr) => (filter(e, idx, arr) ? pass : fail).push(e));
      return [pass, fail];
    }
    
    //Run it with some dummy data and filter
    const [lessThan5, greaterThanEqual5] = partition([0,1,4,3,5,7,9,2,4,6,8,9,0,1,2,4,6], e => e < 5);
    
    //Output
    console.log(lessThan5);
    console.log(greaterThanEqual5);

    0 讨论(0)
  • 2020-12-01 12:06

    ONE-LINER Partition

    const partition = (a,f)=>a.reduce((p,q)=>(p[+!f(q)].push(q),p),[[],[]]);
    

    DEMO

    // to make it consistent to filter pass index and array as arguments
    const partition = (a, f) =>
        a.reduce((p, q, i, ar) => (p[+!f(q, i, ar)].push(q), p), [[], []]);
    
    console.log(partition([1, 2, 3, 4, 5], x => x % 2 === 0));
    console.log(partition([..."ABCD"], (x, i) => i % 2 === 0));

    For Typescript

    const partition = <T>(
      a: T[],
      f: (v: T, i?: number, ar?: T[]) => boolean
    ): [T[], T[]] =>
      a.reduce((p, q, i, ar) => (p[+!f(q, i, ar)].push(q), p), [[], []]);
    
    0 讨论(0)
  • 2020-12-01 12:07

    I ended up doing this because it's easy to understand (and fully typed with typescript).

    const partition = <T>(array: T[], isValid: (element: T) => boolean): [T[], T[]] => {
      const pass: T[] = []
      const fail: T[] = []
      array.forEach(element => {
        if (isValid(element)) {
          pass.push(element)
        } else {
          fail.push(element)
        }
      })
      return [pass, fail]
    }
    
    // usage
    const [pass, fail] = partition([1, 2, 3, 4, 5], (element: number) => element > 3)
    
    0 讨论(0)
  • 2020-12-01 12:10

    What about this?

    [1,4,3,5,3,2].reduce( (s, x) => { s[ x > 3 ].push(x); return s;} , {true: [], false:[]} )
    

    Probably this is more efficient then the spread operator

    Or a bit shorter, but uglier

    [1,4,3,5,3,2].reduce( (s, x) => s[ x > 3 ].push(x)?s:s , {true: [], false:[]} )
    
    
    0 讨论(0)
  • 2020-12-01 12:14

    You can use reduce for it:

    function partition(array, callback){
      return array.reduce(function(result, element, i) {
        callback(element, i, array) 
          ? result[0].push(element) 
          : result[1].push(element);
    
            return result;
          }, [[],[]]
        );
     };
    

    Update. Using ES6 syntax you also can do that using recursion:

    function partition([current, ...tail], f, [left, right] = [[], []]) {
        if(current === undefined) {
            return [left, right];
        }
        if(f(current)) {
            return partition(tail, f, [[...left, current], right]);
        }
        return partition(tail, f, [left, [...right, current]]);
    }
    
    0 讨论(0)
提交回复
热议问题