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
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)
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);
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));
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), [[], []]);
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)
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:[]} )
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]]);
}