Ouracademy

La función filter

La función filter es uno de los Higher Order Functions (HOF) comúnes, aunque inicialmente no estaban en muchos lenguajes de programación, hoy en día están prácticamente en todos. Java (8+), Javascript, C# (3+), Ruby, Python, ... Smalltalk, Lisp.

Asi que, que son las funciones filter?. Que tal si lo explicamos con un ejemplo. Uno muy sencillo: obtener los números pares de la siguiente lista de números.

// Por ejemplo en javascript
var numbers = [1, 2, 3, 4, 5, 8, 2];

A 1ra vista, uno podría resolverlo usando los clásicos for loops, el código quiza podría ser algo como:

var result = [];

for (var i = 0; i < numbers.length; i++) {
  var number = numbers[i];
  if (number % 2 === 0) {
    result.push(number); // agrega number al arreglo result
  }
}

console.log(result);

Bastante verboso, uno podría mejorarlo usando los for each, en javascript usando for of (en otros lenguajes, por ejemplo Java algo asi for(Elemento e : lista)):

let result = [];

for (let number of numbers) {
  if (number % 2 === 0) {
    result.push(number);
  }
}

console.log(result);

Un poco mejor no? Que tal si movemos esa lógica de obtener si un número es par, en una función even:

const even = number => number % 2 === 0;

let result = [];

for (let number of numbers) {
  if (even(number)) {
    result.push(number);
  }
}

console.log(result);

Imagina que nos digan de los mismos números, obtener los números primos. Usando la misma lógica tendriamos algo como:

const prime = number => // aqui la lógica...

let result = [];

for (let number of numbers) {
  if (prime(number)) {
    result.push(number);
  }
}

console.log(result);

Nose si te des cuenta que el for, el if y el push (agregar al resultado) se está volviendo a repetir. Si quisieramos obtener los números > 18 o los números múltiples de 3, volveríamos a repetir otra vez lo mismo. Si movieramos esa lógica a un método...

const filter = (numbers, predicate) => {
  let result = [];

  for (let number of numbers) {
    if (predicate(number)) {
      result.push(number);
    }
  }
  return result;
};

Donde predicate es una función que recibe un elemento (en este caso un número) y retorna un booleano. Podriamos reusar esta función siempre. Por ejemplo, con este nuevo método podríamos obtener los números pares y primos de la siguiente forma:

const even = number => number % 2 === 0;
let result = filter(numbers, even);
console.log(result);

// de hecho podriamos ponerlo en 1 sola linea..
console.log(filter(numbers, even));
// de la misma forma los primos
console.log(filter(numbers, prime));

Que tal? Mejoro bastante.. Bueno ahora si podemos contestar a la pregunta que es una función filter?

Es una función que toma una secuencia (e.g. arrays, listas, streams...) y retorna una nueva secuencia que contiene exactamente aquellos elementos de la secuencia original para los cuales el predicado retorna true.

Un poco complicado? En el 1er ejemplo, la secuencia seria el array numbers, el predicado even (es número par?), y la nueva secuencia seria el nuevo array result.... filter simplemente obtendría aquellos elementos de la secuencia numbers para los que even retorna true, los números pares!

De hecho la mayoría de lenguajes de hoy, tienen esa función filter. Por ejemplo en javascript, usamos array.filter(predicate). En algunos lenguajes tienen otro nombre (select, find all, where) o son más verbosos, pero en general, cumplen esta función. Que tal si vemos unos ejemplos, en otros lenguajes?

En ruby (o quiza usando find_all)

evens = [1,2,3,4,5,8,2].select { |i| i%2 == 0 }

En c# (de distintas formas)

// (1) Usando Array.FindAll:
var numbers = new int[] {1,2,3,4,5,8,2};
var evens = Array.FindAll(numbers, n => n % 2 == 0);

// (2) O Where:
evens = numbers.Where(n => n % 2 == 0);

// (3) a traves de list comprehension:
evens = from n in numbers where n % 2 == 0 select n;

En PHP

$evens = array_filter([1,2,3,4,5,8,2], function ($x) { return $x % 2 == 0;  });

En javascript (ES6)

const evens = numbers.filter(x => x % 2 == 0);

Que tal python?

evens = filter(lambda x: x%2 == 0, [1,2,3,4,5,8,2])
# o usando list comprenhension
evens = [x for x in [1,2,3,4,5,8,2] if x%2 == 0]

En java

// java 8
IntStream evens = IntStream.of(10, 2, 4, 9, 1).filter(n -> n % 2 == 0);
int evens[] = IntStream.of(10, 2, 4, 9, 1).filter(n -> n % 2 == 0).toArray();

// java 11
var evens = IntStream.of(10, 2, 4, 9, 1).filter(n -> n % 2 == 0);

A tu opinión cual se entiende mejor 😉

Si te fue útil este artículo, por favor compártelo. Apreciamos los comentarios y el aliento.
Compartelo por: