Digamos que tengo la siguiente matriz de objetos:
[ { status: 'Draft', order: 1 }, { status: 'Accepted', order: 2 }, { status: 'Ordered', order: 3 }, { status: 'Ordered', order: 4 }, { status: 'Sent', order: 5 } ]Me preguntaba, me gustaría desduplicar objetos dentro de esta matriz, pero solo desduplicar el objeto "más antiguo" con un estado duplicado, es decir, para la matriz anterior, me gustaría terminar con la siguiente de- matriz engañada:
[ { status: 'Draft', order: 1 }, { status: 'Accepted', order: 2 }, { status: 'Ordered', order: 4 }, { status: 'Sent', order: 5 } ]Es decir, el estado Ordenado 4 es "más joven" que el estado Ordenado 3... y no simplemente para desduplicar... esto podría extenderse a lo siguiente:
[ { status: 'Draft', order: 1 }, { status: 'Accepted', order: 2 }, { status: 'Ordered', order: 3 }, { status: 'Ordered', order: 4 }, { status: 'Ordered', order: 5 }, { status: 'Confirmed', order: 6 } ]resultará en:
[ { status: 'Draft', order: 1 }, { status: 'Accepted', order: 2 }, { status: 'Ordered', order: 5 }, { status: 'Confirmed', order: 6 } ]NB Hay una advertencia, en realidad no tengo la clave de orden en el objeto, esto es puramente con fines demostrativos para demostrar lo que quiero decir a los efectos de esta pregunta.
Función de reducción bastante simple. Básicamente creamos un objeto (que solo puede tener un valor por clave). Se conservará la "última" entrada en su matriz con un estado específico.
const input = [ { status: 'Draft', order: 1 }, { status: 'Accepted', order: 2 }, { status: 'Ordered', order: 3 }, { status: 'Ordered', order: 4 }, { status: 'Ordered', order: 5 }, { status: 'Confirmed', order: 6 } ]; const output = Object.values(input.reduce((a, e) => { a[e.status] = e; return a; }, {})); console.log(output);Una sola línea con un mapa:
const arr = [ { status: 'Draft', order: 1 }, { status: 'Accepted', order: 2 }, { status: 'Ordered', order: 3 }, { status: 'Ordered', order: 4 }, { status: 'Ordered', order: 5 }, { status: 'Confirmed', order: 6 } ]; const deduped = [...new Map(arr.map(o => [o.status, o])).values()]; console.log(deduped);JS no incluye una función de desduplicación/distinción de forma nativa, por lo que debe crear la suya propia, como usar un filtro para verificar si hay duplicados.
la devolución de llamada estándar para el filtro es (item, index, array)
esto significa que puedes hacer
filter((item,idx,arr)=> arr.findIndex(other=>areEqual(item,other)) != idx)esto se lee como eliminar todos los elementos donde existieron previamente en la matriz porque findIndex devuelve la ubicación de la primera coincidencia, por lo que si el índice actual no es igual, entonces no es la primera coincidencia
el motivo de findindex en lugar de indexOf es que findIndex le permite especificar cómo verificar la igualdad
aquí es donde entra la devolución de llamada areEqual, toma 2 elementos y devuelve verdadero si son iguales
así podría ser
areEqual(a,b){ return a.field === b.field }por supuesto, esto es excesivo para solo a.field === b.field y podría reescribirse como
filter((item,idx,arr)=> arr.findIndex(other=>item.field === other.field) != idx)pero indica que su prueba de igualdad podría ser más compleja que un solo campo conocido, por lo que la devolución de llamada a areEqual permite una lógica mucho más compleja
desafortunadamente no hay un findLastIndex pero simplemente invirtiendo la matriz antes de filtrar arreglará eso, luego invierta el resultado para recuperar el orden original