Aprende leyendo en orden

Ordenar y buscar — sort / find / some / every

Aprende sort, que ordena según una función de comparación, toSorted, que conserva el original, find y findIndex, que devuelven una coincidencia, y some y every.

Si ordenas una lista con un bucle for que intercambia elementos, tienes que encargarte tú de las comparaciones y de los intercambios cada vez. Buscar el único elemento que cumple una condición te lleva al mismo tipo de código: un bucle for con un break para salir en cuanto lo encuentras.

En este artículo verás sort, que reordena un array, y find, que busca un elemento que cumple una condición.

Indicar el orden con una función — sort y la función de comparación

Supón que quieres mostrar una lista de productos ordenada del más barato al más caro. Un método de array se encarga de ordenar, pero si solo escribes products.sort(), no se ordena por precio, porque no le has dicho qué debe comparar.

A sort (un método que reordena los elementos de un array) le pasas una función de comparación (una función que recibe 2 elementos y devuelve un número). Si llamas a y b a los 2 elementos que recibe, un valor de retorno negativo pone primero a a y uno positivo pone primero a b. Si devuelves a.price - b.price, obtienes los precios en orden ascendente.

const products = [
  { name: "Mouse inalámbrico", price: 2980 },
  { name: "Batería portátil", price: 4380 },
  { name: "Cable USB-C", price: 980 },
  { name: "Pad para mouse", price: 2980 },
];

// Si la resta es negativa, a va primero; si es positiva, va primero b
products.sort((a, b) => a.price - b.price);
console.log(products.map((item) => item.price).join(", "));  // 980, 2980, 2980, 4380

// Comprueba el orden de los 2 productos con el mismo precio
console.log(products[1].name, products[2].name);             // Mouse inalámbrico Pad para mouse

// Si inviertes la resta, obtienes el orden descendente
products.sort((a, b) => b.price - a.price);
console.log(products[0].name);                               // Batería portátil
El número que devuelve la función de comparación decide el orden
Comparación:a.price - b.pricea vale 980b vale 2980a vale 2980b vale 2980a vale 4380b vale 980-2000Devuelve negativo0Sin diferencia3400Devuelve positivoa va primeroConserva elorden originalb va primero
La misma función de comparación devuelve un número distinto según los precios de los 2 elementos que recibe. Dos elementos cuya diferencia es 0 conservan el orden que tenían antes de ordenar.

sort solo se fija en el signo del número devuelto, así que -2000 y -1 se tratan igual. Si también quieres controlar el orden de los productos con el mismo precio, haz que la función de comparación compare otro valor cuando la diferencia sea 0.

Ordena las publicaciones de una app de compraventa en el orden en que aparecerán en pantalla. listings ya está declarado.

① Ordena por el número de caracteres del nombre del producto, de menos a más, y muestra los nombres unidos con ", ".

② Ordena por precio, del más barato al más caro, y muestra los nombres de la misma forma.

③ Vuelve a ordenar por precio, pero esta vez ordena las publicaciones con el mismo precio por likes, de más a menos, y muestra los nombres de la misma forma.

(Si se ejecuta correctamente, aparecerá una explicación.)

Editor JavaScript / TypeScript

Ejecutar el código para ver el resultado

Llamar a sort sin argumentos — la comparación por defecto y toSorted

Supón que quieres ordenar, de menor a mayor, un array con los segundos de permanencia en una página. Si llamas a sort() sin función de comparación, el resultado no sale en orden numérico: 1180 segundos queda antes que 25 segundos.

Sin función de comparación, sort primero convierte los elementos en cadenas y luego las compara carácter por carácter. 1180 se trata como "1180" y 25 como "25", así que el orden lo deciden el 1 y el 2 iniciales. sort reordena el propio array sobre el que se llama, así que si también quieres conservar el orden original, usa toSorted (un método que devuelve un array nuevo ya ordenado).

const viewSeconds = [1180, 980, 25, 4380];

// Sin función de comparación, se comparan como cadenas
console.log(viewSeconds.sort().join(", "));                 // 1180, 25, 4380, 980

// Si pasas una función de comparación, se ordenan como números
console.log(viewSeconds.sort((a, b) => a - b).join(", "));  // 25, 980, 1180, 4380

// toSorted devuelve un array nuevo y no cambia el original
const stayTimes = [1180, 980, 25, 4380];
console.log(stayTimes.toSorted((a, b) => a - b).join(", "));  // 25, 980, 1180, 4380
console.log(stayTimes.join(", "));                            // 1180, 980, 25, 4380
La función de comparación cambia lo que se compara
Escribessort()Los números pasana ser cadenasCompara 1180 y 25desde el inicio1180 quedaadelantePasas(a, b) => a - bLos restacomo números1180 - 25 espositivo25 vaprimero
Los mismos 1180 y 25 se comparan como tipos de valor distintos según si pasas o no una función de comparación. Cada fila pone primero un elemento distinto.

Una vez convertidos en cadenas, "1180" siempre queda antes que "25", así que pasa una función de comparación cuando ordenes un array de números. El segundo sort del código de arriba vuelve a ordenar viewSeconds, que ya había quedado reordenado por la primera llamada.

Cómo afectan sort y toSorted al array
viewSeconds.sort(...)Reescribe elmismo arrayDevuelve esemismo arrayEl orden originalse pierdestayTimes.toSorted(...)Solo lee elarray originalDevuelve unarray nuevoEl orden originalse conserva
Lo que devuelve sort en la fila de arriba es el propio viewSeconds reordenado. Solo toSorted crea un array nuevo.

Los navegadores antiguos no tienen toSorted

toSorted se añadió a la especificación en ES2023, y en los navegadores antiguos que no lo admiten, la línea que lo llama lanza un TypeError. Para que también funcione en esos entornos, llama a sort sobre una copia hecha con la sintaxis spread, como en [...stayTimes].sort((a, b) => a - b).

Ordena una lista de IDs de socios y una lista de existencias, y muestra los resultados. memberIds y stockCounts ya están declarados.

① Ordena memberIds sin pasar una función de comparación y muéstralo unido con ", ".

② Crea un array nuevo y ordenado a partir de stockCounts sin pasar una función de comparación, y muéstralo de la misma forma.

③ Crea un array nuevo a partir de stockCounts ordenado de menor a mayor, y muéstralo de la misma forma.

④ Muestra el primer elemento de stockCounts.

Editor JavaScript / TypeScript

Ejecutar el código para ver el resultado

Obtener el elemento que coincide — find y findIndex

Supón que quieres obtener una reservación a partir de su código. Podrías usar filter, pero devuelve un array, así que tendrías que añadir [0] para leer el primer elemento; y si ninguna reservación coincide, obtienes un array vacío.

find (un método que devuelve el primer elemento que cumple una condición) devuelve el propio elemento: el primero para el que el callback devuelve true. Si lo que quieres es su posición, usa findIndex (un método que devuelve la posición del primer elemento que cumple una condición).

const reservations = [
  { code: "RSV-201", room: "Sala de reuniones A" },
  { code: "RSV-202", room: "Sala de reuniones B" },
  { code: "RSV-203", room: "Sala de reuniones C" },
];

// Devuelve el primer elemento para el que el callback devolvió true
const target = reservations.find((item) => item.code === "RSV-202");
console.log(target.room);  // Sala de reuniones B

// Usa findIndex cuando quieras la posición
console.log(reservations.findIndex((item) => item.code === "RSV-202"));  // 1

// Cuando ninguna reservación coincide
console.log(reservations.find((item) => item.code === "RSV-999"));       // undefined
console.log(reservations.findIndex((item) => item.code === "RSV-999"));  // -1
Las llamadas se detienen en cuanto hay una coincidencia
1.º: RSV-201devuelve falsePasa alsiguiente2.º: RSV-202devuelve trueEste elemento esel resultado3.º: RSV-203no se revisaTermina en el2.º elemento
En cuanto el callback devuelve true para el segundo elemento, ya no se llama para el tercero. Cuanto antes esté la coincidencia, menos llamadas se hacen.

find devuelve solo el primer elemento que coincide, así que no sirve para reunir todas las coincidencias cuando hay varias. Usa filter, que devuelve un array, cuando las necesites todas, y find cuando te baste con una.

Si no encuentra nada, obtienes undefined

Si lees directamente el valor que devolvió find, como en target.room, y ningún elemento coincidió, se lanza TypeError: Cannot read properties of undefined (reading 'room'). Compruébalo con if (target) antes de leerlo.

Busca cupones que cumplan una condición. coupons ya está declarado, y un cupón cuya propiedad expired es true ya venció.

① Muestra el porcentaje de descuento del cupón con el código SOCIO15.

② Muestra la posición (contada desde 0) del cupón vencido.

③ Muestra el código del primer cupón que no ha vencido.

④ Busca el cupón con el código NAVIDAD30 y muestra su porcentaje de descuento si existe, o "No encontrado" si no.

Editor JavaScript / TypeScript

Ejecutar el código para ver el resultado

Comprobar todo el array con true o false — some y every

Supón que quieres decidir, según las existencias, si todos los artículos de un pedido pueden enviarse juntos. Podrías reunir con filter los artículos agotados y contarlos, pero lo que buscas no es un array, sino una sola respuesta: true o false.

some (un método que devuelve true si al menos un elemento cumple la condición) y every (un método que devuelve true si todos los elementos cumplen la condición) devuelven un booleano, no un elemento. Puedes usarlos directamente como condición de un if.

const orderItems = [
  { name: "Botella recargable", stock: 12 },
  { name: "Jabón de manos", stock: 0 },
  { name: "Esponja de baño", stock: 5 },
];

// true si al menos uno cumple
console.log(orderItems.some((item) => item.stock === 0));   // true

// true solo si todos cumplen
console.log(orderItems.every((item) => item.stock > 0));    // false

// Con un array vacío, some da false y every da true
console.log([].some((item) => item.stock > 0));             // false
console.log([].every((item) => item.stock > 0));            // true
Dónde dejan de revisar some y every
Llama a some:busca stock 01.º: 12devuelve false2.º: 0devuelve trueDevuelve true,omite el restoLlama a every:¿todos con stock?1.º: 12devuelve true2.º: 0devuelve falseDevuelve false,omite el resto
Tanto some como every tienen su respuesta en el segundo elemento, que tiene 0 existencias. every termina en cuanto encuentra un elemento que no cumple.

Con un array vacío, ningún elemento cumple la condición, así que some da false; y tampoco hay ninguno que no la cumpla, así que every da true. La tabla de abajo resume lo que devuelven los 4 métodos de búsqueda de este artículo.

MétodoDevuelveSi ningún elemento coincide
findEl propio primer elemento que coincideundefined
findIndexLa posición del primer elemento que coincide-1
sometrue si al menos uno coincidefalse
everytrue si todos coincidenfalse (true con un array vacío)

Comprueba si todos los estudiantes de un curso en línea pueden recibir su certificado, según las tareas entregadas y el porcentaje de asistencia. learners ya está declarado.

① Muestra si todos los estudiantes entregaron al menos una tarea.

② Muestra si hay algún estudiante con 0 entregas.

③ Muestra el nombre del estudiante con 0 entregas.

④ Muestra si el porcentaje de asistencia de todos los estudiantes es del 80% o más.

Editor JavaScript / TypeScript

Ejecutar el código para ver el resultado
QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1Cuando la función de comparación devuelve un valor negativo, ¿qué elemento pone primero sort?

Pregunta 2Si llamas a sort() sobre [1180, 980, 25] sin función de comparación, ¿en qué orden quedan?

Pregunta 3¿Qué método usas para comprobar, con un solo booleano, si todos los productos tienen al menos 1 unidad en existencia?