En este tutorial vamos a ver cómo puedes eliminar tanto elementos de tipo primitivo duplicados como objetos duplicados de un array con JavaScript, una tarea bastante habitual. Para ello crearemos un nuevo array que contenga todos los elementos de original salvo aquellos que estén repetidos.
Contenidos
Elimina elementos duplicados
Para lograr eliminar los duplicados podemos usar varios métodos. A continuación puedes ver algunos de los métodos más utilizados.
Usa un bucle for
El bucle for
suele ser la opción escogida cuando se desconocen otros métodos. Su uso es muy sencillo, aunque no es la opción más elegante.
Primero veremos el código para eliminar elementos de tipo primitivo. Luego lo usaremos para crear una función y un método.
Lo que haremos será recorrer el array y agregar cada elemento a un nuevo array siempre y cuando no exista ya en el mismo, para lo cual nos valdremos del método includes
:
const numeros = [1, 2, 2, 3, 4, 4, 5];
const unicos = [];
for(var i = 0; i < numeros.length; i++) {
const elemento = numeros[i];
if (!unicos.includes(numeros[i])) {
unicos.push(elemento);
}
}
console.log(unicos); // [1, 2, 3, 4, 5]
También podemos crear una función que elimine los elementos duplicados del array mediante un bucle for
, de modo que podamos usarla en más ocasiones:
const numeros = [1, 2, 2, 3, 4, 4, 5];
const eliminaDuplicados = (arr) => {
const unicos = [];
for(var i = 0; i < arr.length; i++) {
const elemento = arr[i];
if (!unicos.includes(arr[i])) {
unicos.push(elemento);
}
}
return unicos;
}
console.log(eliminaDuplicados(numeros)); // [1, 2, 3, 4, 5]
Finalmente, también podemos agregar un método al objeto Array
de JavaScript usando el método prototype
, estando disponible para todos los arrays que creemos:
const numeros = [1, 2, 2, 3, 4, 4, 5];
Array.prototype.unicos = function () {
const unicos = [];
for(i = 0; i < this.length; i++) {
const valor = this[i];
if (unicos.indexOf(valor) < 0) {
unicos.push(valor);
}
}
return unicos;
}
console.log(numeros.unicos()); // [1, 2, 3, 4, 5]
Usa el método filter
El método filter
es un método nativo de los arrays en JavaScript. Es una opción más elegante que un bucle, ya que reduce el gran medida el código necesario. El método filter
está disponible para todos los arrays de JavaScript.
Este método creará un array con los elementos de nuestro array original que cumplan la condición que especifiquemos. Si el método devuelve true
, se agregará el elemento al array resultante. De lo contrario se descartará. La condición se especifica mediante una función que se ejecutará para cada elemento.
Para eliminar los elementos duplicados del array con el método filter
usaremos una función como parámetro del mismo que se ejecutará para cada uno de los elementos del array. Esta función acepta como parámetro el valor y el índice del elemento que se está procesando, siendo el propio método filter
el que se encarga de ejecutar la función en cada iteración.
En nuestro caso insertaremos cada valor en el nuevo array salvo que un elemento ya haya sido agregado previamente al mismo. Para realizar esta comprobación usamos el método indexOf
, que devolverá el índice del primer elemento encontrado con el valor que usemos como parámetro. Si dicho índice coincide con el del elemento actual, devolvemos true
. De lo contrario devolvemos false
.
const numeros = [1, 2, 2, 3, 4, 4, 5];
const unicos = numeros.filter((valor, indice) => {
return numeros.indexOf(valor) === indice;
}
);
console.log(unicos); // [1, 2, 3, 4, 5]
Sin embargo, el método indexOf
no es eficiente cuando un array contiene muchos elementos. En su lugar podemos usar una tabla hash, comprobando al instante si un elemento existe o no en el nuevo array en el que insertamos los elementos:
const numeros = [1, 2, 2, 3, 4, 4, 5];
const tabla = {};
const unicos = numeros.filter((indice) => {
return tabla.hasOwnProperty(indice) ? false : (tabla[indice] = true);
});
console.log(unicos); // [1, 2, 3, 4, 5]
También podríamos crear una función que elimine los elementos duplicados del array usando el método filter
, de modo que podamos usarla en más ocasiones:
const numeros = [1, 2, 2, 3, 4, 4, 5];
const eliminaDuplicados = (arr) => {
return arr.filter((valor, indice) => {
return arr.indexOf(valor) === indice;
});
}
console.log(eliminaDuplicados(numeros)); // [1, 2, 3, 4, 5]
Al igual que hemos hecho en el caso del bucle for
, también podemos agregar un nuevo método al objeto Array
de JavaScript que elimine los elementos duplicados con el método filter
. Así estará disponible para todos los arrays que declaremos:
const numeros = [1, 2, 2, 3, 4, 4, 5];
Array.prototype.unicos = function () {
return this.filter((valor, indice) => {
return this.indexOf(valor) === indice;
});
}
console.log(numeros.unicos()); // [1, 2, 3, 4, 5]
Usa una estructura Set
Otro método mediante el que eliminar elementos duplicados consiste en usar la estructura Set
de JavaScript ES6, que permite crear conjuntos de valores únicos. Lo primeros que haremos será crear un nuevo conjunto usando nuestro array como parámetro. Cuando se cree el conjunto se eliminarán automáticamente los valores duplicados.
Seguidamente, creamos un nuevo array usando el operador spread de propagación ...
que nos permite obtener los elementos del conjunto mediante destructuring.
const numeros = [1, 2, 2, 3, 4, 4, 5];
const unicos = [... new Set(numeros)];
console.log(unicos); // [1, 2, 3, 4, 5]
Para aquellos a quienes este código les resulte complicado, aquí está otra versión alterantiva:
const numeros = [1, 2, 2, 3, 4, 4, 5];
const conjunto = new Set(numeros);
const unicos = [... conjunto];
console.log(unicos); // [1, 2, 3, 4, 5]
Ahora vamos a crear una función que elimine los elementos duplicados del array haciendo uso del método filter
, pudiendo así usarla en más ocasiones:
const numeros = [1, 2, 2, 3, 4, 4, 5];
const eliminaDuplicados = (arr) => {
return [... new Set(arr)];
}
console.log(eliminaDuplicados(numeros)); // [1, 2, 3, 4, 5]
Ahora agregaremos un método al objeto Array
de JavaScipt que elimine los duplicados usando la estructura Set, estando disponible para todos los arrays. Para ello usaremos el método prototype
:
const numeros = [1, 2, 2, 3, 4, 4, 5];
Array.prototype.unicos = function () {
return [... new Set(this)];
}
console.log(numeros.unicos()); // [1, 2, 3, 4, 5]
Usa un bucle forEach
Si prefieres un método más clásico, siempre puedes usar un bucle forEach
, que es un método presente en todos los arrays de JavaScript. El bucle foreach
nos permitirá recorrer los elementos del array con una función en la que podemos agregar aquellos elementos que no se repitan a un nuevo array.
En el siguiente ejemplo recorremos el array numeros
con un bucle foreach
, en el que usamos una función que se ejecutará para cada elemento del array. Vamos a agregar cada elemento a un nuevo array al que llamaremos unicos
siempre que no exista ya en el mismo, para lo cual usaremos del método includes
:
const numeros = [1, 2, 2, 3, 4, 4, 5];
const unicos = [];
numeros.forEach( (elemento) => {
if (!unicos.includes(elemento)) {
unicos.push(elemento);
}
});
console.log(unicos); // [1, 2, 3, 4, 5]
También podemos crear una función para eliminar los elementos duplicados del array mediante un bucle foreach
:
const numeros = [1, 2, 2, 3, 4, 4, 5];
const eliminaDuplicados = (arr) => {
const unicos = [];
arr.forEach( (elemento) => {
if (!unicos.includes(elemento)) {
unicos.push(elemento);
}
});
return unicos;
}
console.log(eliminaDuplicados(numeros)); // [1, 2, 3, 4, 5]
En este otro ejemplo usamos el método prototype
de JavaScript para agregar un método al prototipo del objeto Array
de JavaScript, de modo que el método que agreguemos esté disponible para todos los arrays:
const numeros = [1, 2, 2, 3, 4, 4, 5];
Array.prototype.unicos = function () {
const unicos = [];
this.forEach( (elemento) => {
if (!unicos.includes(elemento)) {
unicos.push(elemento);
}
});
return unicos;
}
console.log(numeros.unicos()); // [1, 2, 3, 4, 5]
Usa el método reduce
El método reduce
itera los elementos del array y ejecuta una función que pasaremos como parámetro con cada uno de ellos. Dicha función acepta como parámetros un acumulador y el elemento actual del array. El valor del acumulador se mantendrá con cada iteración, por lo que es un método que resulta útil para calcular totales. Sin embargo en nuestro caso, el acumulador, que inicialmente estará vacío, será un array en donde almacenaremos los elementos que no se repitan.
En este ejemplo usamos el método reduce
con el acumulador accArr
, que contendrá los elementos únicos que vayamos agregando. Para comprobar si un valor ya existe en el array accArr
, usamos el método indexOf
. Si no está, lo insertamos. Para inicializar el array accArr
, usamos un array vacío []
como segundo parámetro de la función del método reduce.
const numeros = [1, 2, 2, 3, 4, 4, 5];
const unicos = numeros.reduce( (accArr, valor) => {
if (accArr.indexOf(valor) < 0) {
accArr.push(valor);
}
return accArr;
}, []);
console.log(unicos); // [1, 2, 3, 4, 5]
A continuación crearemos una función para eliminar los elementos duplicados del array usando el método reduce
:
const numeros = [1, 2, 2, 3, 4, 4, 5];
const eliminaDuplicados = (arr) => {
return numeros.reduce( (accArr, valor) => {
if (accArr.indexOf(valor) < 0) {
accArr.push(valor);
}
return accArr;
}, []);
}
console.log(eliminaDuplicados(numeros)); // [1, 2, 3, 4, 5]
A continuación usamos el método prototype
para agregar un nuevo método al prototipo del objeto Array
de JavaScript. El método que agregaremos, al que llamaremos unicos
, estará disponible para todos los arrays que declaremos, eliminando los duplicados cuando así lo deseemos:
const numeros = [1, 2, 2, 3, 4, 4, 5];
Array.prototype.unicos = function () {
return this.reduce((accArr, valor) => {
if (accArr.indexOf(valor) < 0) {
accArr.push(valor);
}
return accArr;
}, []);
}
console.log(numeros.unicos()); // [1, 2, 3, 4, 5]
Usando Underscore JS
Algunas librerías disponen ya de métodos que te permitirán eliminar los elementos duplicados de un array. Un ejemplo de ello es el método _uniq
de la librería Underscore JS.
const numeros = [1, 2, 2, 3, 4, 4, 5];
console.log(_uniq(numeros, false));
Además, también podemos ordenar el array resultante si el segundo parámetro de la función _uniq
tiene el valor true
en lugar de false
:
console.log(_uniq(numeros, true));
Elimina objetos duplicados
A continuación vamos a ver diversos métodos que nos permitirán eliminar los objetos duplicados de un array. El proceso de eliminación de objetos implica el acceso a sus propiedades, por lo que el proceso difiere de la eliminación de elementos de tipo primitivo.
Usa la estructura map
El objeto Map
se itnrodujo en JavaScript ES6 para guardar pares de clave y valor, guardando también el orden de inserción. Primero usamos un array de arrays como parámetro del objeto Map
, para luego convertirlo en pares de clave y valor, siendo la clave el nombre
. La clave será la propiedad que hace que el objeto esté repetido, pudiendo así asegurarnos de que no habrá elementos repetidos. Finalmente convertimos de nuevo el objeto en un array:
const personas = [
{ nombre: 'Edu', edad: 35, },
{ nombre: 'Manuel', edad: 34, },
{ nombre: 'Edu', edad: 20, },
{ nombre: 'Manuel', edad: 52, },
];
let personasMap = personas.map(item=>{
return [item.nombre,item]
});
var personasMapArr = new Map(personasMap); // Pares de clave y valor
let unicos = [...personasMapArr.values()]; // Conversión a un array
console.log(unicos);
/*
[
{ nombre: "Edu" , edad: 35 },
{ nombre: "Manuel", edad: 34 }
]
*/
Si queremos que un objeto se considere como repetido cuando todas sus propiedades son iguales, tendremos que usar el siguiente el método JSON.stringify
, que convertirá todo el objeto en una cadena de texto que podemos usar como clave de cada elemento de la estructura Map
. De este modo, los elementos que difieran en una única propiedad de otros no serán reemplazados:
const personas = [
{ nombre: 'Edu', edad: 35, },
{ nombre: 'Manuel', edad: 34, },
{ nombre: 'Edu', edad: 20, },
{ nombre: 'Manuel', edad: 34, },
];
let personasMap = personas.map(persona => {
return [JSON.stringify(persona), persona]
});
let personasMapArr = new Map(personasMap); // Pares de clave y valor
let unicos = [...personasMapArr.values()]; // Conversión a un array
console.log(unicos);
/*
[
{ nombre: "Edu" , edad: 35 },
{ nombre: "Manuel", edad: 34 },
{ nombre: "Edu" , edad: 20 },
]
*/
A continuación vamos a ver cómo representar los dos casos que hemos visto como una función.
La siguiente función sirve para eliminar duplicados usando la estructura Map
cuando especificamos una propiedad que identifica a los objetos como duplicados. la función debe adaptarse a cada tipo de objeto; no puede usarse como función genérica:
const personas = [
{ nombre: 'Edu', edad: 35, },
{ nombre: 'Manuel', edad: 34, },
{ nombre: 'Edu', edad: 20, },
{ nombre: 'Manuel', edad: 34, },
];
const eliminaPersonasDuplicadas = (arr) => {
const personasMap = arr.map(persona => {
return [persona.nombre, persona]
});
return [...new Map(personasMap).values()];
}
console.log(eliminaPersonasDuplicadas(personas));
/*
[
{ nombre: "Edu" , edad: 20 },
{ nombre: "Manuel", edad: 34 },
]
*/
Función que elimina duplicados usando la estructura Map
cuando basta que una de las propiedades sea diferente para que el objeto se considere duplicado. Puede usarse como función genérica, ya que es independiente del contenido de los objetos:
const personas = [
{ nombre: 'Edu', edad: 35, },
{ nombre: 'Manuel', edad: 34, },
{ nombre: 'Edu', edad: 20, },
{ nombre: 'Manuel', edad: 34, },
];
const eliminaDuplicados = (arr) => {
const arrMap = arr.map(elemento => {
return [JSON.stringify(elemento), elemento]
});
return [...new Map(arrMap).values()];
}
console.log(eliminaDuplicados(personas));
/*
[
{ nombre: "Edu" , edad: 35 },
{ nombre: "Manuel", edad: 34 },
{ nombre: "Edu" , edad: 20 },
]
*/
Usa Set
/ reduce
Vamos a eliminar objetos duplicados usando el método Set
, que permite crear conjuntos con claves úncias, eliminando automáticamente los elementos duplicados. En el siguiente ejemplo, un elemento se consdiera duplicado cuando la propiedad nombre
es la misma. Para llevar a cabo dicha tarea usaremos el método reduce
, en cuyo interior agregaremos los elementos del array al conjunto seObj
, cuya clave será la propiedad nombre
. De este modo evitamos que se repitan las claves:
const personas = [
{ nombre: 'Edu', edad: 35, },
{ nombre: 'Manuel', edad: 34, },
{ nombre: 'Edu', edad: 20, },
{ nombre: 'Manuel', edad: 34, },
];
const setObj = new Set(); // creamos pares de clave y array
const unicos = personas.reduce((acc, persona) => {
if (!setObj.has(persona.nombre)){
setObj.add(persona.nombre, persona)
acc.push(persona)
}
return acc;
},[]);
console.log(unicos);
/*
[
{ nombre: "Edu" , edad: 35 },
{ nombre: "Manuel", edad: 34 },
]
*/
En caso de querer que el objeto se considere como repetido cuando todas sus propiedades sean iguales, tendremos que usar el siguiente el método JSON.stringify
para transformar todo el objeto en una cadena que usaremos como clave en la estructura Set
:
const personas = [
{ nombre: 'Edu', edad: 35, },
{ nombre: 'Manuel', edad: 34, },
{ nombre: 'Edu', edad: 20, },
{ nombre: 'Manuel', edad: 34, },
];
const setObj = new Set(); // creamos pares de clave y array
const unicos = personas.reduce((acc, persona) => {
const clave = JSON.stringify(persona);
if (!setObj.has(clave)){
setObj.add(clave, persona)
acc.push(persona)
}
return acc;
},[]);
Veamos ahora cómo representar los dos casos anteriores mediante una función. La función que ves a continuación sirve para eliminar duplicados usando el método reduce
y la estructura Set
en el caso de que los objetos se consideran duplicados cuando una única propiedad específica se repite. En nuestro ejemplo, dicha propiedad es la propiedad nombre
:
const personas = [
{ nombre: 'Edu', edad: 35, },
{ nombre: 'Manuel', edad: 34, },
{ nombre: 'Edu', edad: 20, },
{ nombre: 'Manuel', edad: 34, },
];
const eliminaPersonasDuplicadas = (arr) => {
const setObj = new Set();
return personas.reduce((acc, persona) => {
if (!setObj.has(persona.nombre)){
setObj.add(persona.nombre, persona)
acc.push(persona)
}
return acc;
},[]);
}
console.log(eliminaPersonasDuplicadas(personas));
/*
[
{ nombre: "Edu" , edad: 35 },
{ nombre: "Manuel", edad: 34 },
]
*/
En el siguiente ejemplo, un objeto se considerará duplicado cuando todas sus propiedades sean idénticas. Puede usarse como método genérico de eliminación de objetos duplicados con cualquier array que contanga objetos:
const personas = [
{ nombre: 'Edu', edad: 35, },
{ nombre: 'Manuel', edad: 34, },
{ nombre: 'Edu', edad: 20, },
{ nombre: 'Manuel', edad: 34, },
];
const eliminaDuplicados = (arr) => {
const setObj = new Set(); // creamos pares de clave y array
return arr.reduce((acc, elemento) => {
const clave = JSON.stringify(elemento);
if (!setObj.has(clave)){
setObj.add(clave, elemento)
acc.push(elemento)
}
return acc;
},[]);
}
console.log(eliminaDuplicados(personas));
/*
[
{ nombre: "Edu" , edad: 35 },
{ nombre: "Manuel", edad: 34 },
{ nombre: "Edu" , edad: 20 },
]
*/
Usa un bucle for
Veamos también cómo duplicados usando un bucle for
cuando el array contiene objetos. En el siguiente ejemplo consideramos que una persona está duplicada si su nombre es el mismo. Lo que haremos será recorrer el array personas, agregando cada elemento no duplicado al array unicos
. Una persona estará duplicada si ya existe una persona con el mismo nombre en el array unicos
, por lo que tendremos que recorrerlo con cada iteración del bucle principal.
Lo lógica es la misma que la que hemos usado para eliminar elementos de tipo primitivo.
const personas = [
{ nombre: 'Edu', edad: 35, },
{ nombre: 'Manuel', edad: 34, },
{ nombre: 'Edu', edad: 20, },
{ nombre: 'Manuel', edad: 52, },
];
const unicos = [];
for(var indice = 0; indice < personas.length; indice++) {
const persona = personas[indice];
let esDuplicado = false;
for(var i = 0; i < unicos.length; i++) {
if (unicos[i].nombre === persona.nombre) {
esDuplicado = true;
break;
}
}
if (!esDuplicado) {
unicos.push(persona);
}
}
console.log(unicos);
/*
[
{ nombre: "Edu", edad: 35, },
{ nombre: "Manuel", edad: 34 }
]
*/
La siguiente función eliminará los objetos de tipo persona
duplicados mediante un bucle for
:
const personas = [
{ nombre: 'Edu', edad: 35, },
{ nombre: 'Manuel', edad: 34, },
{ nombre: 'Edu', edad: 20, },
{ nombre: 'Manuel', edad: 52, },
];
const eliminaDuplicados = (arr) => {
const unicos = [];
for(var indice = 0; indice < personas.length; indice++) {
const persona = personas[indice];
let esDuplicado = false;
for(var i = 0; i < unicos.length; i++) {
if (unicos[i].nombre === persona.nombre) {
esDuplicado = true;
break;
}
}
if (!esDuplicado) {
unicos.push(persona);
}
}
return unicos;
}
console.log(eliminaDuplicados(personas));
/*
[
{ nombre: "Edu", edad: 35, },
{ nombre: "Manuel", edad: 34 },
]
*/
Usando Underscore JS
Si usas la librería Underscore JS también puedes usar el método _uniq
para obtener un array sin duplicados basándote en alguna propiedad del objeto:
const personas = [
{ nombre: 'Edu', edad: 35, },
{ nombre: 'Manuel', edad: 34, },
{ nombre: 'Edu', edad: 20, },
{ nombre: 'Manuel', edad: 34, },
];
const unicos = _.uniq(personas, function(persona){
return persona.nombre;
});
console.log(unicos);
/*
[
{ nombre: "Edu" , edad: 35 },
{ nombre: "Manuel", edad: 34 },
{ nombre: "Edu" , edad: 20 },
]
*/
Y esto ha sido todo.
Hola me ayudas a entender como puedo hacer esto. mi funcion debe tener 2 parametros
function mergeData(users, attendances)
Mezclando datos de 2 arreglos
La función mergeData() recibe como parámetros 2 arreglos:
El primer arreglo es una lista de usuarios con una estructura como la siguiente
[
{ name: ‘Georg’, email: ‘georg@academlo.com’ },
{ name: ‘Andrea’, email: ‘andrea@gmail.com’ }
]
El segundo arreglo es una lista de asistencias con una estructura como la siguiente, donde attendance nos indica si el usuario asistió o no a sus clases de programación
[
{ email: ‘georg@academlo.com’, attendance: true },
{ email: ‘andrea@gmail.com’, attendance: false }
]
Tu labor es hacer una mezcla de los datos de ambos arreglos y devolver uno solo que contenga toda la información (sin datos duplicados).
Ejemplo:
En el caso de haber recibido los 2 arreglos mencionados anterior mente deberas retornar el siguiente arreglo:
[
{ name: ‘Georg’, email: ‘georg@academlo.com’, attendance: true },
{ name: ‘Andrea’, email: ‘andrea@gmail.com’, attendance: false }
]
*Recuerda utilizar return para devolver tu solución.
*El primer arreglo que recibe la función puede tener n cantidad de usuarios.
*El segundo arreglo que recibe la función puede tener n cantidad de asistencias.