JavaScript

JavaScript

Tutorial JavaScript: Filtrado con filter() y find()

JavaScript filtrado: técnicas y ejemplos. Aprende técnicas de filtrado en JavaScript con ejemplos prácticos y detallados.

Aprende JavaScript y certifícate

Fundamentos de filtrado en arrays: Sintaxis y diferencias entre filter() y find()

Los arrays en JavaScript ofrecen métodos integrados para buscar y filtrar elementos según criterios específicos. Dos de los más útiles son filter() y find(), que aunque parecen similares, tienen propósitos y comportamientos distintos.

Método filter()

El método filter() examina todos los elementos de un array y devuelve un nuevo array con aquellos que cumplen una condición determinada. Este método no modifica el array original, siguiendo los principios de la programación funcional.

La sintaxis básica es:

const newArray = array.filter(callback);

Donde callback es una función que se ejecuta para cada elemento y debe devolver true o false. El callback recibe tres parámetros:

array.filter((element, index, array) => {
  // Lógica que devuelve true o false
});
  • element: El elemento actual que se está procesando
  • index: La posición del elemento en el array
  • array: El array completo sobre el que se llamó a filter()

Veamos un ejemplo práctico:

const numbers = [1, 2, 3, 4, 5, 6, 7, 8];
const evenNumbers = numbers.filter(num => num % 2 === 0);

console.log(evenNumbers); // [2, 4, 6, 8]

En este caso, filter() crea un nuevo array que contiene solo los números pares del array original.

También podemos filtrar objetos basándonos en sus propiedades:

const products = [
  { name: 'Laptop', price: 1200, inStock: true },
  { name: 'Phone', price: 800, inStock: false },
  { name: 'Tablet', price: 500, inStock: true }
];

const availableProducts = products.filter(product => product.inStock);
console.log(availableProducts); // [{ name: 'Laptop'... }, { name: 'Tablet'... }]

Método find()

A diferencia de filter(), el método find() devuelve el primer elemento que cumple con la condición especificada. Si ningún elemento cumple la condición, devuelve undefined.

La sintaxis es similar a filter():

const element = array.find(callback);

El callback recibe los mismos parámetros que en filter():

array.find((element, index, array) => {
  // Lógica que devuelve true o false
});

Veamos un ejemplo:

const numbers = [5, 12, 8, 130, 44];
const firstLargeNumber = numbers.find(num => num > 10);

console.log(firstLargeNumber); // 12

Observa que aunque hay varios números mayores que 10 en el array, find() solo devuelve el primero que encuentra (12).

Para buscar objetos por sus propiedades:

const users = [
  { id: 1, name: 'Alice', role: 'admin' },
  { id: 2, name: 'Bob', role: 'user' },
  { id: 3, name: 'Charlie', role: 'user' }
];

const admin = users.find(user => user.role === 'admin');
console.log(admin); // { id: 1, name: 'Alice', role: 'admin' }

Diferencias clave entre filter() y find()

  • Valor de retorno: filter() devuelve un array (posiblemente vacío), mientras que find() devuelve un único elemento o undefined.

  • Comportamiento de búsqueda: filter() examina todos los elementos del array, mientras que find() se detiene en cuanto encuentra el primer elemento que cumple la condición.

  • Caso de no coincidencia: Si ningún elemento cumple la condición, filter() devuelve un array vacío [], mientras que find() devuelve undefined.

const numbers = [1, 3, 5, 7];

// Ningún número es par
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // []

const firstEven = numbers.find(num => num % 2 === 0);
console.log(firstEven); // undefined
  • Rendimiento: Para grandes conjuntos de datos, find() puede ser más eficiente cuando solo necesitas el primer elemento que coincida, ya que deja de iterar una vez que lo encuentra.

Cuándo usar cada método

Usa filter() cuando:

  • Necesites todos los elementos que cumplan una condición
  • Quieras crear un subconjunto de datos basado en ciertos criterios
  • Debas realizar operaciones posteriores sobre múltiples elementos filtrados
// Obtener todos los productos con descuento para mostrarlos en una sección especial
const discountedProducts = products.filter(product => product.discount > 0);

Usa find() cuando:

  • Busques un elemento específico (como un usuario por ID)
  • Solo necesites la primera coincidencia
  • Sepas que solo existe un elemento que cumple la condición
// Buscar un producto específico por su ID
const product = inventory.find(item => item.id === productId);

Predicados simples

Los predicados son las funciones que devuelven true o false y que pasamos a filter() o find(). Para casos sencillos, podemos usar expresiones lambda (funciones flecha):

// Predicado simple con filter()
const adults = people.filter(person => person.age >= 18);

// Predicado simple con find()
const sarah = people.find(person => person.name === 'Sarah');

Estos métodos de filtrado son fundamentales para el manejo de datos en JavaScript moderno y constituyen la base para operaciones más complejas de transformación y procesamiento de colecciones.

Construcción de predicados eficientes: Funciones de filtrado para casos simples y complejos

Los predicados son funciones que evalúan una condición y devuelven un valor booleano, siendo fundamentales para las operaciones de filtrado en JavaScript. Construir predicados eficientes mejora tanto la legibilidad como el rendimiento de nuestro código.

Predicados para casos simples

Para situaciones básicas, las funciones flecha ofrecen una sintaxis concisa y expresiva:

// Filtrar números positivos
const positiveNumbers = numbers.filter(num => num > 0);

// Encontrar el primer producto disponible
const firstAvailable = products.find(product => product.available);

Cuando necesitamos reutilizar predicados, es recomendable extraerlos como funciones independientes:

// Predicado reutilizable
const isPremiumUser = user => user.subscription === 'premium';

// Uso en múltiples contextos
const premiumUsers = users.filter(isPremiumUser);
const firstPremiumUser = users.find(isPremiumUser);

Esta técnica mejora la mantenibilidad del código y facilita las pruebas unitarias de la lógica de filtrado.

Predicados parametrizados

Para crear filtros más flexibles, podemos implementar funciones que generen predicados:

// Generador de predicados para filtrar por precio
const priceAbove = threshold => product => product.price > threshold;

// Uso con diferentes umbrales
const expensiveProducts = products.filter(priceAbove(1000));
const midRangeProducts = products.filter(priceAbove(500));

Este patrón aprovecha los cierres (closures) de JavaScript para crear predicados configurables según nuestras necesidades.

Predicados compuestos

Para condiciones más complejas, podemos combinar predicados mediante operadores lógicos:

// Predicados individuales
const isInStock = product => product.stock > 0;
const isOnSale = product => product.discount > 0;

// Combinación con operadores lógicos
const availableDeals = products.filter(product => isInStock(product) && isOnSale(product));

También podemos crear funciones de composición para mejorar la legibilidad:

// Funciones para componer predicados
const and = (predA, predB) => item => predA(item) && predB(item);
const or = (predA, predB) => item => predA(item) || predB(item);
const not = pred => item => !pred(item);

// Uso de predicados compuestos
const isExpensive = product => product.price > 1000;
const isExpensiveAndInStock = and(isExpensive, isInStock);
const budgetOrOnSale = or(not(isExpensive), isOnSale);

const premiumAvailable = products.filter(isExpensiveAndInStock);
const goodDeals = products.filter(budgetOrOnSale);

Optimización de predicados

Para mejorar el rendimiento en conjuntos de datos grandes, podemos implementar estrategias de optimización:

  • Evaluación temprana: Colocar las condiciones más discriminantes primero
// Menos eficiente: evaluación compleja primero
const inefficientFilter = items.filter(item => 
  complexCalculation(item) && item.simple === true
);

// Más eficiente: evaluación simple primero
const efficientFilter = items.filter(item => 
  item.simple === true && complexCalculation(item)
);
  • Evitar cálculos redundantes en predicados:
// Ineficiente: recalcula para cada elemento
const inefficient = data.filter(item => {
  const result = expensiveOperation();
  return item.value > result;
});

// Eficiente: calcula una sola vez
const threshold = expensiveOperation();
const efficient = data.filter(item => item.value > threshold);

Predicados para estructuras anidadas

Para filtrar datos con estructuras complejas, podemos crear predicados específicos:

// Filtrar por propiedad anidada
const hasActiveTasks = user => 
  user.tasks && user.tasks.some(task => task.status === 'active');

const usersWithPendingWork = users.filter(hasActiveTasks);

También podemos implementar búsquedas profundas en estructuras jerárquicas:

// Buscar comentarios de un autor específico en una estructura anidada
const findCommentsByAuthor = authorId => {
  const searchComments = item => {
    // Verificar el elemento actual
    if (item.author === authorId) return true;
    
    // Buscar recursivamente en respuestas
    if (item.replies && item.replies.length > 0) {
      return item.replies.some(searchComments);
    }
    
    return false;
  };
  
  return searchComments;
};

const aliceComments = comments.filter(findCommentsByAuthor('alice123'));

Predicados con contexto

En ocasiones necesitamos acceder a un contexto durante el filtrado:

// Filtrar elementos relacionados con el elemento seleccionado
function getRelatedItems(items, selectedId) {
  const selectedItem = items.find(item => item.id === selectedId);
  
  if (!selectedItem) return [];
  
  return items.filter(item => 
    item.id !== selectedId && 
    item.category === selectedItem.category
  );
}

const relatedProducts = getRelatedItems(catalog, 'prod-457');

Predicados para casos de uso específicos

Para búsquedas de texto, podemos crear predicados que manejen diferentes casos:

// Búsqueda insensible a mayúsculas/minúsculas
const containsText = searchText => item => {
  const search = searchText.toLowerCase();
  return item.title.toLowerCase().includes(search) || 
         item.description.toLowerCase().includes(search);
};

const searchResults = items.filter(containsText('javascript'));

Para filtrado por rango de valores:

// Filtrar por rango de precios
const priceRange = (min, max) => product => 
  product.price >= min && product.price <= max;

const midRangeItems = products.filter(priceRange(100, 500));

Estos patrones de construcción de predicados nos permiten crear filtros expresivos y mantenibles que se adaptan a la complejidad de nuestros datos y requisitos de negocio.

Integración con el ecosistema funcional: Combinación de filter() y find() con otros métodos de array

La verdadera potencia de los métodos filter() y find() se manifiesta cuando los combinamos con otros métodos funcionales de arrays en JavaScript. Esta integración permite crear flujos de procesamiento de datos elegantes y expresivos que transforman, filtran y extraen información de manera declarativa.

Encadenamiento de métodos funcionales

El encadenamiento (chaining) es una técnica fundamental en programación funcional que permite aplicar múltiples operaciones secuenciales a una colección de datos:

const transactions = [
  { id: 1, amount: 100, type: 'purchase', category: 'food' },
  { id: 2, amount: 50, type: 'refund', category: 'electronics' },
  { id: 3, amount: 200, type: 'purchase', category: 'electronics' },
  { id: 4, amount: 25, type: 'purchase', category: 'food' }
];

// Obtener el total de compras en electrónica
const totalElectronicsPurchases = transactions
  .filter(t => t.type === 'purchase' && t.category === 'electronics')
  .map(t => t.amount)
  .reduce((sum, amount) => sum + amount, 0);

console.log(totalElectronicsPurchases); // 200

En este ejemplo, combinamos filter() para seleccionar transacciones específicas, map() para extraer los montos y reduce() para sumarlos, creando un pipeline de datos claro y conciso.

Combinación con map() para transformación

La combinación de filter() con map() permite filtrar y transformar datos en una secuencia fluida:

const products = [
  { id: 1, name: 'Laptop', price: 1200, stock: 5 },
  { id: 2, name: 'Phone', price: 800, stock: 0 },
  { id: 3, name: 'Tablet', price: 500, stock: 12 },
  { id: 4, name: 'Headphones', price: 150, stock: 8 }
];

// Obtener nombres de productos disponibles con precio formateado
const availableProductsInfo = products
  .filter(p => p.stock > 0)
  .map(p => ({
    name: p.name,
    formattedPrice: `$${p.price.toFixed(2)}`
  }));

console.log(availableProductsInfo);
// [
//   { name: 'Laptop', formattedPrice: '$1200.00' },
//   { name: 'Tablet', formattedPrice: '$500.00' },
//   { name: 'Headphones', formattedPrice: '$150.00' }
// ]

Uso de find() con destructuring

Podemos combinar find() con destructuring para extraer elementos específicos de manera elegante:

const users = [
  { id: 1, name: 'Alice', permissions: ['read', 'write'] },
  { id: 2, name: 'Bob', permissions: ['read'] },
  { id: 3, name: 'Charlie', permissions: ['admin', 'read', 'write'] }
];

// Buscar un usuario con permisos de administrador
const { name, permissions } = users.find(user => 
  permissions.includes('admin')
) || { name: 'Unknown', permissions: [] };

console.log(`Admin user: ${name}`); // Admin user: Charlie

El operador || proporciona un valor predeterminado en caso de que no se encuentre ningún usuario administrador.

Integración con sort() para filtrado y ordenamiento

Combinar filter() con sort() permite filtrar y ordenar datos en una sola cadena de operaciones:

const tasks = [
  { id: 1, title: 'Fix bug', priority: 'high', completed: false },
  { id: 2, title: 'Write docs', priority: 'medium', completed: true },
  { id: 3, title: 'Test feature', priority: 'high', completed: false },
  { id: 4, title: 'Deploy app', priority: 'medium', completed: false }
];

// Obtener tareas pendientes ordenadas por prioridad
const pendingTasksByPriority = tasks
  .filter(task => !task.completed)
  .sort((a, b) => {
    const priorityValues = { high: 3, medium: 2, low: 1 };
    return priorityValues[b.priority] - priorityValues[a.priority];
  });

console.log(pendingTasksByPriority.map(t => t.title));
// ['Fix bug', 'Test feature', 'Deploy app']

Combinación con some() y every()

Los métodos filter() y find() se complementan perfectamente con some() y every() para validaciones complejas:

const team = [
  { name: 'Alice', skills: ['javascript', 'react', 'node'] },
  { name: 'Bob', skills: ['python', 'data analysis'] },
  { name: 'Charlie', skills: ['javascript', 'vue', 'css'] }
];

// Verificar si al menos un miembro tiene habilidades en React
const hasReactDeveloper = team.some(member => 
  member.skills.includes('react')
);

// Encontrar miembros que conocen JavaScript y filtrar sus nombres
const javascriptDevs = team
  .filter(member => member.skills.includes('javascript'))
  .map(member => member.name);

console.log(hasReactDeveloper); // true
console.log(javascriptDevs); // ['Alice', 'Charlie']

Patrones avanzados con flatMap()

El método flatMap() combina map() y flat(), permitiendo transformar y aplanar estructuras anidadas:

const departments = [
  { name: 'Engineering', employees: [
    { name: 'Alice', role: 'Frontend' },
    { name: 'Bob', role: 'Backend' }
  ]},
  { name: 'Marketing', employees: [
    { name: 'Charlie', role: 'Content' }
  ]},
  { name: 'HR', employees: [] }
];

// Obtener todos los empleados de ingeniería
const engineeringEmployees = departments
  .find(dept => dept.name === 'Engineering')
  ?.employees || [];

// Obtener todos los empleados de todos los departamentos
const allEmployees = departments
  .flatMap(dept => dept.employees)
  .map(emp => `${emp.name} (${emp.role})`);

console.log(allEmployees);
// ['Alice (Frontend)', 'Bob (Backend)', 'Charlie (Content)']

Composición funcional con filter() y find()

Podemos crear funciones de utilidad que compongan operaciones de filtrado y búsqueda:

// Función para filtrar y luego encontrar un elemento
const filterAndFind = (array, filterFn, findFn) => 
  array.filter(filterFn).find(findFn);

// Función para encontrar y luego filtrar elementos relacionados
const findAndFilterRelated = (array, findFn, relationFn) => {
  const found = array.find(findFn);
  return found ? array.filter(item => relationFn(item, found)) : [];
};

// Ejemplo de uso
const products = [
  { id: 1, category: 'electronics', price: 1200, brand: 'Apple' },
  { id: 2, category: 'electronics', price: 800, brand: 'Samsung' },
  { id: 3, category: 'books', price: 20, brand: null },
  { id: 4, category: 'electronics', price: 600, brand: 'Samsung' }
];

// Encontrar el primer producto Samsung de más de 700€
const expensiveSamsung = filterAndFind(
  products,
  p => p.brand === 'Samsung',
  p => p.price > 700
);

// Encontrar productos similares al producto con id 2
const similarProducts = findAndFilterRelated(
  products,
  p => p.id === 2,
  (item, found) => item.id !== found.id && item.brand === found.brand
);

console.log(similarProducts);
// [{ id: 4, category: 'electronics', price: 600, brand: 'Samsung' }]

Integración con async/await

Para operaciones asíncronas, podemos combinar filter() y find() con Promise.all() y async/await:

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'Charlie' }
];

// Función asíncrona para obtener permisos
const fetchUserPermissions = async (userId) => {
  // Simulación de llamada a API
  const permissions = {
    1: ['read', 'write'],
    2: ['read'],
    3: ['read', 'write', 'admin']
  };
  
  return new Promise(resolve => {
    setTimeout(() => resolve(permissions[userId] || []), 100);
  });
};

// Encontrar usuarios con permisos de administrador
const findAdmins = async (users) => {
  // Obtener permisos para todos los usuarios
  const usersWithPermissions = await Promise.all(
    users.map(async user => ({
      ...user,
      permissions: await fetchUserPermissions(user.id)
    }))
  );
  
  // Filtrar usuarios administradores
  return usersWithPermissions.filter(user => 
    user.permissions.includes('admin')
  );
};

// Uso
findAdmins(users).then(admins => {
  console.log(admins); // [{ id: 3, name: 'Charlie', permissions: [...] }]
});

La integración de filter() y find() con otros métodos funcionales crea un ecosistema coherente para el procesamiento de datos, permitiendo escribir código más declarativo, mantenible y expresivo que refleja claramente la intención del desarrollador.

CONSTRUYE TU CARRERA EN IA Y PROGRAMACIÓN SOFTWARE

Accede a +1000 lecciones y cursos con certificado. Mejora tu portfolio con certificados de superación para tu CV.

30 % DE DESCUENTO

Plan mensual

19.00 /mes

13.30 € /mes

Precio normal mensual: 19 €
63 % DE DESCUENTO

Plan anual

10.00 /mes

7.00 € /mes

Ahorras 144 € al año
Precio normal anual: 120 €
Aprende JavaScript online

Ejercicios de esta lección Filtrado con filter() y find()

Evalúa tus conocimientos de esta lección Filtrado con filter() y find() con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Funciones flecha

JavaScript
Puzzle

Polimorfismo

JavaScript
Test

Array

JavaScript
Código

Transformación con map()

JavaScript
Test

Gestor de tareas con JavaScript

JavaScript
Proyecto

Manipulación DOM

JavaScript
Test

Funciones

JavaScript
Test

Funciones flecha

JavaScript
Código

Async / Await

JavaScript
Código

Creación y uso de variables

JavaScript
Test

Excepciones

JavaScript
Puzzle

Promises

JavaScript
Código

Funciones cierre (closure)

JavaScript
Test

Herencia

JavaScript
Puzzle

Herencia

JavaScript
Test

Estructuras de control

JavaScript
Código

Selección de elementos DOM

JavaScript
Test

Modificación de elementos DOM

JavaScript
Test

Filtrado con filter() y find()

JavaScript
Test

Funciones cierre (closure)

JavaScript
Puzzle

Funciones

JavaScript
Puzzle

Mapas con Map

JavaScript
Test

Reducción con reduce()

JavaScript
Test

Callbacks

JavaScript
Puzzle

Manipulación DOM

JavaScript
Puzzle

Promises

JavaScript
Test

Async / Await

JavaScript
Test

Eventos del DOM

JavaScript
Puzzle

Async / Await

JavaScript
Puzzle

Promises

JavaScript
Puzzle

Filtrado con filter() y find()

JavaScript
Código

Callbacks

JavaScript
Test

Creación de clases y objetos Restaurante

JavaScript
Código

Reducción con reduce()

JavaScript
Código

Filtrado con filter() y find()

JavaScript
Puzzle

Reducción con reduce()

JavaScript
Puzzle

Conjuntos con Set

JavaScript
Puzzle

Herencia de clases

JavaScript
Código

Eventos del DOM

JavaScript
Test

Clases y objetos

JavaScript
Puzzle

Modificación de elementos DOM

JavaScript
Puzzle

Mapas con Map

JavaScript
Puzzle

Introducción a JavaScript

JavaScript
Test

Funciones

JavaScript
Código

Tipos de datos

JavaScript
Test

Clases y objetos

JavaScript
Test

Array

JavaScript
Test

Conjuntos con Set

JavaScript
Test

Array

JavaScript
Puzzle

Encapsulación

JavaScript
Puzzle

Clases y objetos

JavaScript
Código

Uso de operadores

JavaScript
Puzzle

Uso de operadores

JavaScript
Test

Estructuras de control

JavaScript
Test

Excepciones

JavaScript
Test

Transformación con map()

JavaScript
Puzzle

Funciones flecha

JavaScript
Test

Selección de elementos DOM

JavaScript
Puzzle

Encapsulación

JavaScript
Test

Mapas con Map

JavaScript
Código

Creación y uso de variables

JavaScript
Puzzle

Polimorfismo

JavaScript
Puzzle

Tipos de datos

JavaScript
Puzzle

Estructuras de control

JavaScript
Puzzle

Todas las lecciones de JavaScript

Accede a todas las lecciones de JavaScript y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a JavaScript y certifícate

Certificados de superación de JavaScript

Supera todos los ejercicios de programación del curso de JavaScript y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.

En esta lección

Objetivos de aprendizaje de esta lección

  1. Comprender el uso y funcionamiento de los métodos filter() y find() en JavaScript.
  2. Aprender a utilizar filter() para crear un nuevo array con elementos filtrados que cumplan una condición dada.
  3. Aprender a utilizar find() para obtener el primer elemento que cumpla una condición especificada.
  4. Conocer la sintaxis y uso de funciones flecha como argumentos para filter() y find() para hacer el código más conciso y fácil de leer.
  5. Familiarizarse con los parámetros que pueden recibirse en las funciones de llamada (callbacks) de filter() y find(), como el elemento actual del array, el índice y el array en sí, y cómo pueden utilizarse para escribir funciones más avanzadas.