Revista Informática

Métodos para operar sobre arrays en JavaScript de forma eficiente

Publicado el 04 noviembre 2019 por Daniel Rodríguez @analyticslane

A la hora de trabajar con vectores de objetos el paradigma declarativo utilizado habitualmente el JavaScript puede ser un poco pesado. En estos suele ser más cómodo utilizar paradigma de programación funcional. JavaScript dispone de múltiples métodos para utilizar programación funcional, algunos de los más conocidos son map(), reduce(), filter() y find(). En esta entrada se va a mostrar como utilizar estos métodos para operar sobre arrays en JavaScript de forma eficiente.

La programación funcional

En su gran mayoría el código JavaScript se escribe bajo el paradigma declarativo. Un paradigma en el que cada línea es una instrucción en un proceso que ha de ser ejecutada en un orden concreto. En muchas ocasiones el orden de ejecución de las instrucciones puede ser indiferente, como puede ser a la hora de sumar los números de un vector.

Tradicionalmente estos problemas se resuelven mediante la utilización de un bucle. Pero los métodos de programación funcional permiten hacer esto de forma más eficiente. Para trabajar bajo este paradigma JavaScript disponemos de los métodos filter(), find(), map(), reduce(), every() y some() cuyo funcionamiento básico se explicará a continuación.

El método filter() permite buscar a los registros de un array que cumple una condición. Devolviendo como resultado un nuevo array con estos elementos.

A modo de ejemplo se puede utilizar un listado de clientes generado aleatoriamente para buscar aquellos que hubiesen gastado más de una cantidad. En el siguiente ejemplo se muestra cómo utilizar filter().

const clients = [{
	"id": 1,
	"name": "Adria Zack",
	"amount": 22.68
}, {
	"id": 2,
	"name": "Libby Willerstone",
	"amount": 11.91
}, {
	"id": 3,
	"name": "Antonetta Brandli",
	"amount": 6.91
}, {
	"id": 4,
	"name": "June Moverley",
	"amount": 7.93
}, {
	"id": 5,
	"name": "Kendrick Lindell",
	"amount": 18.13
}];
	
const spend = clients.filter(client => {
	return client.amount > 10;
});

// El resultado en spend es
// [ { id: 1, name: 'Adria Zack', amount: 22.68 },
//   { id: 2, name: 'Libby Willerstone', amount: 11.91 },
//   { id: 5, name: 'Kendrick Lindell', amount: 18.13 } ]

Lo primero que vemos es que filter() es un método del array al que hay que inyectar una función para aplicar sobre cada uno de los elementos que devuelve un valor verdadero o falso. Siendo seleccionados únicamente los elementos en los que la función devuelve el valor verdadero.

A pesar de ser un código ya compacto la función se puede simplificar. Como el método solamente tiene una línea se pueden eliminar las llaves y la palabra clave return.

const spend = clients.filter(client => client.amount > 10)

Esta línea devuelve los mismos resultados que todas la anteriores, pero es más compacta. Lo que permite dejar el código mucho más compacto y legible.

Cuando solamente se desea identificar un registro que verifica la condición se puede utilizar find() en lugar de filter(). A diferencia del caso anterior el método no devuelve un array sino que el primer objeto que cumpla con la condición. Aplicando este método en el ejemplo anterior se obtendría.

const first = clients.find(client => client.amount > 10);

// El resultado en first es
// { id: 1, name: 'Adria Zack', amount: 22.68 }

Si solamente se quiere comprobar que se cumple una condición se puede utilizar el método every(). Este método devuelve verdadero si todos los registros cumplen con la condición indicada o falso en caso contrario. Lo que permite comprobar si todos los clientes han realizado un gasto mínimo dato.

clients.every(client => client.amount > 5)  // true
clients.every(client => client.amount > 10) // false

En la primera línea el resultado es verdadero porque todos los clientes han gastado más de 5. Pero no así en la segunda, ya que hay clientes que han gastado menos de 10.

Por otro lado para comprobar si algún registro cumple una condición se utilizará el método some(). Este devuelve verdadero si algún registro cumple la condición y falso en caso contrario.

clients.some(client => client.amount > 10) // true
clients.some(client => client.amount > 30) // false

El método map() permite aplicar la función a cada uno de los registros y devolverá un nuevo array con los resultados. Por ejemplo, se puede obtener fácilmente un array con el nombre de los clientes.

const names = clients.map(client => client.name);

// El resultado en names es
// [ 'Adria Zack',
//   'Libby Willerstone',
//   'Antonetta Brandli',
//   'June Moverley',
//   'Kendrick Lindell' ]

Finalmente, para obtener un único resultado se dispone del método reduce(). El cual es ligeramente diferente a los vistos anteriormente. En primer lugar, la función a inyectar requiere dos parámetros. El primero es el resultado del paso anterior y el segundo es el elemento evaluado actualmente. Como en la primera iteración no hay un valor previo se pasan los dos elementos del array.

Este método se puede utilizar para obtener el gasto total de los clientes. Lo que se puede hacer como se muestra a continuación.

const amount = clients.reduce((a, b) => {
	return { "amount": a.amount + b.amount };
});

// El resultado en amount es
//  { amount: 67.56 }

Otra alternativa es evaluar si la primera entrada es un elemento del array o un número.

const totalamount = clients.reduce((a, b) => {
	if (a.hasOwnProperty('amount')){
		return a.amount + b.amount;
	}else{
		return a + b.amount;
	}
});

Combinación de los métodos para operar sobre arrays en JavaScript

Si estos métodos son ya potentes por sí solos juntos lo son aún más. Es posible combinar todos ellos para crear complejas operaciones con poco código. Por ejemplo, obtener el nombre de los clientes que han comprado más de una cantidad. Para lo que en primer lugar es necesario aplicar el método filter() y posteriormente el método map(). Antes de aplicar el método map() no es necesario guardar los datos en una variable ya se puede aplicar directamente sobre la salida del método filter().

const names_10 = clients.filter(client => client.amount > 10).map(client => client.name);

Conclusiones

En esta entrada se han visto seis métodos para operar sobre arrays en JavaScript que permite producir código más compacto y claro. Una de las grandes ventajas de la programación funcional. Aunque hay que tener en cuenta que suelen ser más lentos que los bucles for, como se muestra en esta comparativa del rendimiento de los métodos de iteración en JavaScript. Salvo que el rendimiento sea clave y se trabaje con una cantidad enorme de registros estos métodos son una buena solución para mejorar nuestro código.

Imágenes: Pixabay (pasja1000)


Volver a la Portada de Logo Paperblog