Array Methods

Verificar si un valor existe en un arreglo

Digamos que tenemos el siguiente arreglo de índices y otro arreglo de objetos y queremos saber si un determinado valor existe, como podría ser “Enero”.

const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio'];

Lo podríamos detectar con un for loop de la siguiente manera:

const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio'];

meses.forEach(mes => {
    if(mes === 'Enero') {
        console.log('Enero sí existe...')
    }
})

Pero JavaScript tiene sus propios método para estas cosas, tal como:

El método .includes() para detectar si un valor existe en un array de index

Si tenemos un arreglo como el anterior podríamos usar .includes() para que retorne un boolean si un valor existe o no.

const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio'];
const resultado = meses.includes('Enero'); 
console.log(resultado);

Si cambiamos el mes por uno que no exista, el valor será false.

El método .some() para detectar si un valor existe en un objeto dentro de un arreglo

Pero si tenemos un arreglo que contiene objetos como se muestra abajo, entonces el método .inclujdes() no nos ayuda, y para ello tenemos el método .some().

Pero este método trabaja con una arrow function que chequea los valores de los objetos y retorna un valor de array al momento de encontrar una coincidencia o cumplirse una condición.

const carrito = [
    { nombre: 'Monitor 20 Pulgadas', precio: 500},
    { nombre: 'Televisión 50 Pulgadas', precio: 700},
    { nombre: 'Tablet', precio: 300},
    { nombre: 'Audifonos', precio: 200},
    { nombre: 'Teclado', precio: 50},
    { nombre: 'Celular', precio: 500},
    { nombre: 'Bocinas', precio: 300},
    { nombre: 'Laptop', precio: 800},
];

const existe = carrito.some( producto => producto.nombre === 'Celular' );
console.log(existe);

Si se busca por un valor que no exista entonces el resultado será false.

No obstante, .some() puede iterar también con arreglos de índices simples.

const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio'];

const existe2 = meses.some( mes => mes === 'Diciembre' );
console.log(existe2);

Dado esto, el método .some() es el más usado a la hora de determinar la existencia de valores dentro de arreglos ya que puede hacerlo si son valores índices o son valores en objetos.

Es de aclara que .some() va a retornar un true en la primera oportunidad que un valor del array cumpla con la condición especificada.

El método .every() para detectar si todos los valores en un arreglo cumplen una condición

El método .every() es lo contrario a .some(), ya que no busca una coincidencia de un valor dado, si no que detecta que todos los valores cumplan con una condición dada, y si es así, retorna un true.

const carrito = [
    { nombre: 'Monitor 20 Pulgadas', precio: 500},
    { nombre: 'Televisión 50 Pulgadas', precio: 700},
    { nombre: 'Tablet', precio: 300},
    { nombre: 'Audifonos', precio: 200},
    { nombre: 'Teclado', precio: 50},
    { nombre: 'Celular', precio: 500},
    { nombre: 'Bocinas', precio: 300},
    { nombre: 'Laptop', precio: 800},
];

// con un foreach seria algo asi...
let cumple = true;
carrito.forEach( producto => {
    if(producto.precio > 700) {
        cumple = false;
        return
    }
})
console.log(cumple);

const resultado = carrito.every(producto => producto.precio < 1000); // True porque se cumple en todos
console.log(resultado);

const resultado2 = carrito.every(producto => producto.precio < 799); // False porque no se cumple en al menos uno
console.log(resultado2);

const resultadoSome = carrito.some( item => item.precio > 700); // True porque se cumple en al menos uno
console.log(resultadoSome);

const resultadoSome2 = carrito.some( item => item.precio > 800); // False porque no se cumple en ninguno
console.log(resultadoSome2);

Devolver el índice de un valor en un arreglo

Si tenemos un arreglo y queremos saber cuál es el índice de un valor determinado podemos usar tanto una estructura for loop, un .forEach() o usar un método específico para ello, .findIndex(), que también funciona para arreglos que contienen objetos.

De los siguientes ejemplos el profesor usó solo un arreglo de índices y expuso el .forEach() y luego el .findIndex(). Yo agregué el for loop y agregué los tres para un arreglo con objetos.

El método .findIndex() para hallar índices de valores dados

Es de destacar que esta parte es para mostrar el método .findIndex(), que se trata de un método, como su nombre lo indica, para hallar el índice de un valor y retornarlo, si determinado valor no es encontrado entonces retorna un -1.

Este método como casi todos los métodos para los arrays, trabaja con arrow functions. Este método tiene la ventaja de que al retornar un índice de -1 si no se encuentra el valor, podemos adecuar el código para que ejecute a consecuencia.

También resulta que como su misión es encontrar el índice, el cual no se repite, entonces no va a continuar con la búsqueda a través del arreglo una vez que lo ha hallado ya que se supone que ese valor no se debe repetir. Eso no pasa con los ejemplos hechos con el for loop y el forEach ya que ellos buscan valores, y luego nosotros adecuamos el código para que me de el índice de ese valor encontrado.

Para ejemplificarlo repetí los valores buscados tanto en el array de índices como en el array de objetos, donde se puede observar que tanto el for loop como el forEach() los encuentra y mostramos los índices pero con el .findIndex() no, solo se muestra el primero,

const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Abril'];

for(let i =0; i<meses.length; i++) {
    if(meses[i] === 'Abril') {
        console.log( `Encontrado ${meses[i]} en el índice ${i} por un bucle for loop` ); } }

meses.forEach( (mes, index) => {
    if(mes === 'Abril') { // Si ponemos diciembre no lo va a encontrar...
        console.log(`Encontrado ${mes} en el indice ${index} por un bucle forEach`);  } } );

const indice = meses.findIndex( mes => mes === 'Abril' ); 
console.log(`Encontrado Abril en el índice ${indice} por el método findIndex`);

const carrito = [
    { producto: 'Monitor 20 Pulgadas', precio: 500},
    { producto: 'Televisión 50 Pulgadas', precio: 700},
    { producto: 'Tablet', precio: 300},
    { producto: 'Audífonos', precio: 200},
    { producto: 'Teclado', precio: 50},
    { producto: 'Celular', precio: 500},
    { producto: 'Bocinas', precio: 300},
    { producto: 'Laptop', precio: 800},
    { producto: 'Tablet', precio: 700}
];

for(let i = 0; i<carrito.length; i++) {
  if(carrito[i].producto === 'Tablet') {
    console.log( `Encontrado ${carrito[i].producto} índice ${i} por un for loop y precio de ${carrito[i].precio}`);}}

carrito.forEach(  (prod, indice) => {
  if(prod.producto === 'Tablet') {
    console.log( `Encontrado ${prod.producto} índice ${indice} por un forEach y precio de ${prod.precio}`)}});

const indice2 = carrito.findIndex( prod =>  prod.producto === 'Tablet' )

if(indice2 === -1){
    console.log( `El método findIndex no encontró el dato solicitado` );
}else{ console.log( `El dato encontrado en el índice ${indice2} por el método findIndex` )}

//Artículo inexistente
const indice3 = carrito.findIndex( prod =>  prod.producto === 'Disco Duro' )

if(indice3 === -1){
    console.log( `El método findIndex no encontró el dato solicitado` );
}else{ console.log( `El dato encontrado en el índice ${indice2} por el método findIndex` )}

El método .reduce()

Este método realiza una operación basado en unos datos dentro de un arreglo, por lo general y por lo que he visto en Mozilla, trabaja con números. Podríamos realizar la suma de todos los números que están como valores en un arreglo. Prácticamente le veo el uso para una suma de todos esos valores. Ya que parte de un valor iniciar, luego realiza una operación y el resultado se agrega al valor previo y así sucesivamente.

En la operación se agrega el valor iniciar, tomé un ejemplo de Mozilla y me doy cuanta que se puede quitar el valor iniciar.

Si se agrega un valor iniciar entonces la función toma el valor prev con esa valor iniciar y current pasa a tener el primer valor del array. Pero puede no especificarse ese primer valor iniciar, con lo que el parámetro prev tomará como argumento el primer valor del array y le parámetro current tomará como primer valor el segundo valor del array.

Si estamos trabajando con un array de objetos entonces obligatoriamente hay que especificar un valor iniciar. Creo que porque no hay manera de que se le pueda indicar al parámetro prev qué valor del objeto va a tomar. Eso se puede especificar con el valor current que por medio de la sintaxis de punto podemos indicar que valor tomar.

Este es uno de esos métodos que prefiero tener una fuente de consulta ya que el mismo es un bicho raro.

Abajo hay un código que usa un array de objetos y la operación se realiza con un .forEach() y luego con .reduce(). Luego se aplica .reduce() a un array de índices y allí quito el valor iniciar donde se observa que se puede para una array con tales valores.

Queremos el total del carrito.

const carrito = [
    { producto: 'Monitor 20 Pulgadas', precio: 500},
    { producto: 'Televisión 50 Pulgadas', precio: 700},
    { producto: 'Tablet', precio: 300},
    { producto: 'Audifonos', precio: 200},
    { producto: 'Teclado', precio: 50},
    { producto: 'Celular', precio: 500},
    { producto: 'Bocinas', precio: 300},
    { producto: 'Laptop', precio: 800},
];

// Con un forEach lo podrías hacer así:

let total = 0;
carrito.forEach( producto => total += producto.precio );
console.log(total);

// Puedes ver que si bien no se ve mal, podemos tenerlo todo en una sola linea con un .reduce
// previo, actual
let resultado = carrito.reduce((total2, prod) => total2 + prod.precio, 0); //0 es el inicio
console.log( resultado );

//Lo mismo pero si el valor iniciar para que de error
let resultadoSinValorIniciar = carrito.reduce((total2, prod) => total2 + prod.precio ); 
console.log( resultadoSinValorIniciar );

// Ahora aplicando .reduce() a un array de índices y donde sí podemos desechar el valor iniciar que por default toma el
// primer valor de la matriz, y current el segundo valor

const array1 = [4, 5, 6, 7];
const reducer = (previousValue, currentValue) => previousValue + currentValue;

// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15

// Simulando la sintaxis del ejemplo con array de objetos y sin valor iniciar 
const reductor = array1.reduce( (prev, current) => prev + current);
console.log(reductor);

El método .filter()

Este método es según el instructor, uno de los que más usaré como programador. Creo bastante que sí. Este método hace un cambio en el array creando una nueva array. El .filter() va a crearte un arreglo basado en un parámetro que es evaluado.

const carrito = [
    { nombre: 'Monitor 20 Pulgadas', precio: 500},
    { nombre: 'Televisión 50 Pulgadas', precio: 700},
    { nombre: 'Tablet', precio: 300},
    { nombre: 'Audifonos', precio: 200},
    { nombre: 'Teclado', precio: 50},
    { nombre: 'Celular', precio: 500},
    { nombre: 'Bocinas', precio: 300},
    { nombre: 'Laptop', precio: 800},
];

let resultado = carrito.filter( producto => producto.precio > 400 ); // Todos los mayores a 400 - añadir  && producto.precio < 600
let resultado2 = carrito.filter( producto => producto.nombre === 'Celular'  ); // Traerte el celular
let resultado3 = carrito.filter(producto => producto.nombre !== 'Laptop'); // Todos menos la laptop

console.log(resultado);
console.log(resultado2);
console.log(resultado3);

Tengo que tomar en cuenta que si se está hablado de que crea un nuevo array entonces tengo que crear una variable para contener ese nuevo array. Lo que me genera la duda sobre la masiva creación de variables para contener un nuevo array cada vez que se modifique. En todo caso podría hacer que la variable original sea igual a la nueva array.

Función de alto nivel con el método .filter()

En una de las prácticas se vio esto del uso de una función de alto nivel que no es más que una función que llama a otras funciones.

En el código de abajo se coloca como argumento en el método filter solo el nombre de otra función sin paréntesis. Esta función tiene el objetivo de retornar la parte condicional que solicita el método filter para realizar el filtrado del arreglo con el que trabaja.

En el ejemplo de abajo las funciones lo que hacen es determinar si ese valor existe en un objeto llamado datosBusqueda, esa es la razón por la que se hace eso. Es decir, filter no realiza la comprobación para el filtrado directamente, si no que le pide a otra función que chequee si ese valor existe en mencionado objeto y si es así entonces que le retorne la comprobación que necesita.

function filtrarAuto() { 
    const resultado = autos.filter( filtrarMarca ).filter( filtrarYear ).filter( filtrarMinimo ).filter( filtrarMaximo ); 
}

function filtrarMarca(datosAutos) {
    const { marca } = datosBusqueda;
     if(marca) {
         return datosAutos.marca === marca;
     }
     return datosAutos;
}

function filtrarYear(datosAutos) {
    const { year } = datosBusqueda;
     if(year) {
         return datosAutos.year === year;
     }
     return datosAutos;
}

function filtrarMinimo(datosAutos) {
    const { minimo } = datosBusqueda;
    if(minimo) {
        return datosAutos.precio >= minimo; 
    }
    return datosAutos;
}

function filtrarMaximo(datosAutos) {
    const { maximo } = datosBusqueda;
    if(maximo) {
        return datosAutos.precio <= maximo;
    }
    return datosAutos;
}

Método .find()

No sé qué le pasa a este instructor, dice que este método crea, bueno: fiND te creará un arreglo nuevo en base al primer resultado que sea true…

Este método lo que hace es que retorna el valor encontrado en un array según una condición que se coloca en la arrow function. De hecho inserté varios typeOf para verificarlo, y no sale nada de array, sale Object o number según el ejemplo. Abajo se incluye un ejemplo de cómo se haría con un forEach.

// fiND te creará un arreglo nuevo en base al primer resultado que sea true...

const carrito = [
    { nombre: 'Monitor 20 Pulgadas', precio: 500},
    { nombre: 'Televisión 50 Pulgadas', precio: 700},
    { nombre: 'Tablet', precio: 300},
    { nombre: 'Audifonos', precio: 200},
    { nombre: 'Teclado', precio: 50},
    { nombre: 'Celular', precio: 500},
    { nombre: 'Bocinas', precio: 300},
    { nombre: 'Laptop', precio: 800},
];
// con un foreach seria algo asi...
let resultado = '';
carrito.forEach((producto, index) => {
    if(producto.nombre === 'Bocinas') {
        resultado = carrito[index]
    }
});
console.log(resultado);

// con .find seria

const resultado2 = carrito.find( producto => producto.nombre === 'Bocinas');
console.log(resultado2);

//Código por Brigzen
console.log(typeof(resultado2)); //Esto es un objeto, no un array

//Código por Brigzen

const arreglo = [1, 2, 3, 4, 5];
const result = arreglo.find(  numero => numero == 5  );
console.log(result);
console.log(typeof(result)); //Un number, no un array

A todas estas es muy fácil de entender este método.

Concatenar arreglos

Método .concat() para concatenar arreglos

No se necesita mucha explicación

const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio'];
const meses2 = ['Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];

// Unir 2 arreglos con concat...
const meses3 = meses.concat(meses2);
console.log(meses3);

El Spread Operator para concatenar arreglos

Tampoco hace falta mayor explicación. Aunque el profesor hace énfasis en que este método no modifica el arreglo original (claro está con el hecho de que se crea otra variable) como sí lo haría el método .push() y que esto es bueno para la programación funcional que se verá más adelante.

// Un poco más sobre el rest operator...

// El rest operator es muy útil para crear un nuevo arreglo sin modificar el original...
const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio'];

const carrito = [
    { producto: 'Monitor 20 Pulgadas', precio: 500},
    { producto: 'Televisión 50 Pulgadas', precio: 700},
    { producto: 'Tablet', precio: 300},
    { producto: 'Audifonos', precio: 200},
    { producto: 'Teclado', precio: 50},
    { producto: 'Celular', precio: 500},
    { producto: 'Bocinas', precio: 300},
    { producto: 'Laptop', precio: 800},
];

// Si tienes 2 arreglos los unes como vimos en el video anterior, pero digamos que tienes un arreglo y quieres añadir un elemento al final que es un string utilizarias...

console.log(meses);

const meses2 = [...meses, 'Julio'];
console.log(meses2); // Recuerda esto no modifica el arreglo original como si haría push y 
                                   // eso es muy útil en un tipo de programación llamada funcional...

// O al inicio... en lugar de utilizar unshift, 
const meses3 = ['Julio',...meses ]; 

// O tal vez quieres añadir un objeto a un arreglo de objetos al final
const producto = {producto: 'Disco Duro', precio: 300};
const carrito2 = [...carrito, producto];
console.log(carrito2);

// o al inicio
const carrito3 = [producto, ...carrito];
console.log(carrito3);

El Spread Operator es solo para extraer los datos de un array, no funciona con un objeto.