ejemplos - map filter and reduce javascript
Dividiendo una matriz por funciĆ³n de filtro (7)
Tengo una matriz de Javascript que me gustaría dividir en dos en función de si una función llamada en cada elemento devuelve true
o false
. Esencialmente, este es un array.filter
, pero también me gustaría tener a mano los elementos que fueron filtrados.
Actualmente, mi plan es usar array.forEach
y llamar a la función de predicado en cada elemento. Dependiendo de si esto es verdadero o falso, empujaré el elemento actual en uno de los dos arreglos nuevos. ¿Hay una forma más elegante o mejor de hacer esto? ¿Un array.filter
donde el elemento empujará a otro array antes de que devuelva false
, por ejemplo?
Con ES6 puedes hacer uso de la sintaxis de propagación con reduce:
function partition(array, isValid) {
return array.reduce(([pass, fail], elem) => {
return isValid(elem) ? [[...pass, elem], fail] : [pass, [...fail, elem]];
}, [[], []]);
}
const [pass, fail] = partition(myArray, (e) => e > 5);
O en una sola línea:
const [pass, fail] = a.reduce(([p, f], e) => (e > 5 ? [[...p, e], f] : [p, [...f, e]]), [[], []]);
En la función de filtro puede empujar sus elementos falsos en otra función externa de variable:
var bad = [], good = [1,2,3,4,5];
good = good.filter(function (value) { if (value === false) { bad.push(value) } else { return true});
Por supuesto, el value === false
necesita ser una comparación real;)
Pero hace casi esa misma operación como forEach
. Creo que deberías usar forEach
para una mejor legibilidad del código.
Esto suena muy similar al método de Enumerable#partition
Ruby .
Si la función no puede tener efectos secundarios (es decir, no puede alterar la matriz original), entonces no hay una manera más eficiente de particionar la matriz que iterar sobre cada elemento y empujar el elemento a una de sus dos matrices.
Dicho esto, podría decirse que es más "elegante" crear un método en Array
para realizar esta función. En este ejemplo, la función de filtro se ejecuta en el contexto de la matriz original (es decir, this
será la matriz original), y recibe el elemento y el índice del elemento como argumentos (similar a each
método de jQuery ):
Array.prototype.partition = function (f){
var matched = [],
unmatched = [],
i = 0,
j = this.length;
for (; i < j; i++){
(f.call(this, this[i], i) ? matched : unmatched).push(this[i]);
}
return [matched, unmatched];
};
console.log([1, 2, 3, 4, 5].partition(function (n, i){
return n % 2 == 0;
}));
//=> [ [ 2, 4 ], [ 1, 3, 5 ] ]
Prueba esto:
function filter(a, fun) {
var ret = { good: [], bad: [] };
for (var i = 0; i < a.length; i++)
if (fun(a[i])
ret.good.push(a[i]);
else
ret.bad.push(a[i]);
return ret;
}
DEMO
Puedes usar lodash.partition
var users = [
{ ''user'': ''barney'', ''age'': 36, ''active'': false },
{ ''user'': ''fred'', ''age'': 40, ''active'': true },
{ ''user'': ''pebbles'', ''age'': 1, ''active'': false }
];
_.partition(users, function(o) { return o.active; });
// → objects for [[''fred''], [''barney'', ''pebbles'']]
// The `_.matches` iteratee shorthand.
_.partition(users, { ''age'': 1, ''active'': false });
// → objects for [[''pebbles''], [''barney'', ''fred'']]
// The `_.matchesProperty` iteratee shorthand.
_.partition(users, [''active'', false]);
// → objects for [[''barney'', ''pebbles''], [''fred'']]
// The `_.property` iteratee shorthand.
_.partition(users, ''active'');
// → objects for [[''fred''], [''barney'', ''pebbles'']]
R.partition(R.contains(''s''), [''sss'', ''ttt'', ''foo'', ''bars'']);
// => [ [ ''sss'', ''bars'' ], [ ''ttt'', ''foo'' ] ]
R.partition(R.contains(''s''), { a: ''sss'', b: ''ttt'', foo: ''bars'' });
// => [ { a: ''sss'', foo: ''bars'' }, { b: ''ttt'' } ]
Puedes usar reducir para ello:
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;
}, [[],[]]
);
};
Se me ocurrió este pequeño chico. Se usa para todos y cada uno de los que describió, pero en mi opinión se ve limpio y conciso.
//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);