136 votes

Diviser un tableau par une fonction filtre

J'ai un tableau Javascript que je voudrais diviser en deux en fonction du retour d'une fonction appelée sur chaque élément. true o false . Il s'agit essentiellement d'un array.filter mais j'aimerais également avoir sous la main les éléments qui ont été filtrés. out .

Actuellement, mon plan est d'utiliser array.forEach et appeler la fonction prédicat sur chaque élément. Selon que cette fonction est vraie ou fausse, je vais pousser l'élément actuel sur l'un des deux nouveaux tableaux. Existe-t-il une manière plus élégante ou meilleure de procéder ? Un site array.filter où le poussera l'élément sur un autre tableau avant de retourner false par exemple ?

102voto

braza Points 633

Avec ES6, vous pouvez utiliser la syntaxe spread avec 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);

Ou sur une seule ligne :

const [pass, fail] = a.reduce(([p, f], e) => (e > 5 ? [[...p, e], f] : [p, [...f, e]]), [[], []]);

56voto

Zoltán Kocsán Points 337

Vous pouvez utiliser 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']]

ou ramda.partition

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

26voto

UDrake Points 231

Je suis venu avec ce petit gars. Il utilise pour chacun et tout ce que vous avez décrit, mais il semble propre et succinct à mon avis.

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

22voto

Yaremenko Andrii Points 141

Vous pouvez utiliser la réduction pour cela :

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

Mise à jour. En utilisant la syntaxe ES6, vous pouvez également le faire en utilisant la récursion (mise à jour pour éviter de créer de nouveaux tableaux à chaque itération) :

function partition([current, ...tail], f, left = [], right = []) {
    if(current === undefined) {
        return [left, right];
    }
    if(f(current)) {
        left.push(current);
        return partition(tail, f, left, right);
    }
    right.push(current);
    return partition(tail, f, left, right);
}

15voto

Brandan Points 8311

Cela ressemble beaucoup à Ruby's Enumerable#partition méthode.

Si la fonction ne peut pas avoir d'effets secondaires (c'est-à-dire qu'elle ne peut pas modifier le tableau original), alors il n'y a pas de moyen plus efficace de partitionner le tableau que d'itérer sur chaque élément et de pousser l'élément dans l'un de vos deux tableaux.

Ceci étant dit, il est sans doute plus "élégant" de créer une méthode sur Array pour exécuter cette fonction. Dans cet exemple, la fonction de filtrage est exécutée dans le contexte du tableau original (c'est-à-dire, this sera le tableau original), et il reçoit l'élément et l'index de l'élément comme arguments (similaire à La méthode de jQuery each méthode ):

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X