Tengo una matriz muy simple:
var arr = [{id: 1, score: 10}, {id: 1, score: 10}, {id: 3, score: 20}, {id: 4, score: 5}];Quiero eliminar los objetos que tienen una sola aparición, por ejemplo:
{id: 3, score: 20} {id: 4, score: 5}Así que el resultado final debería ser:
[{id: 1, score: 10}, {id: 1, score: 10}]Lo que he probado hasta ahora es:
const result = []; for (let i = 0; i < arr.length; i++) { for (let j = i + 1; j < arr.length; j++) { if (arr[i].id === arr[j].id && arr[i].score === arr[j].score) { result.push({ id: arr[i].id, score: arr[i].score }) } } }Pero esto también está eliminando mis duplicados, por ejemplo, me da este resultado:
[{id: 1, score: 10}]Pero necesito este resultado:
[{id: 1, score: 10}, {id: 1, score: 10}]Array.filter ayudará
Filtre la matriz con la combinación de id y score , verifique si la longitud de esta combinación es mayor que 1, lo que significa que hay más de una aparición de esta combinación.
const arr = [{ id: 1, score: 10 }, { id: 1, score: 10 }, { id: 3, score: 20 }, { id: 4, score: 5 }, { id: 77, score: 25, type: 'notthisone' }]; const newArr = arr.filter(item => arr.filter(x => x.id === item.id && x.score === item.score).length > 1 || item.type === 'notthisone'); console.log(newArr);Tu solución fija.
Tienes que empujar el valor de arr tanto para el índice i como para el j . Pero el nodo de índice para i debe presionarse solo una vez.
const arr = [{id: 1, score: 10}, {id: 1, score: 10}, {id: 3, score: 20}, {id: 4, score: 5}, {id: 77, score: 25, type: 'notthisone'}]; const result = []; for (let i = 0; i < arr.length; i++) { let isFound = false; for (let j = i + 1; j < arr.length; j++) { if (arr[i].id === arr[j].id && arr[i].score === arr[j].score) { isFound = true; result.push(arr[j]); } } if(isFound || arr[i].type === 'notthisone') { result.push(arr[i]); } } console.log(result); Editar: si desea tener un objeto específico que tenga un valor particular para el type de clave, puede incluirlo en la condición. He actualizado la respuesta con eso.
Puede tomar un solo bucle y un objeto para realizar un seguimiento de la primera referencia para el mismo elemento.
const array = [{ id: 1, score: 10, x: 1 }, { id: 1, score: 10, x: 2, }, { id: 3, score: 20 }, { id: 4, score: 5 }, { id: 77, score: 25, type: 'notthisone' }], getKey = ({ id, score }) => JSON.stringify({ id, score }), result = array .map((q => o => { if (o.type === 'notthisone') return o; const key = getKey(o), target = []; q[key] ??= { value: undefined, target }; if (q[key].value) { q[key].target[0] ??= q[key].value; return o; } q[key].value = o; return target; })({})) .flat(); console.log(result); .as-console-wrapper { max-height: 100% !important; top: 0; }Puede considerar usar Array.reduce combinado con Array.find ( Array.find es menos 'caro' que Array.filter ). Algo así como (también tomó en cuenta su pregunta sobre la respuesta de @Nitheesh):
const arr = [ {id: 1, score: 10}, {id: 1, score: 10}, {id: 3, score: 20}, {id: 4, score: 5}, {id: 77, score: 25, include: true} ]; const log = document.querySelector(`pre`); log.textContent = `**Reduced\n${ JSON.stringify(retrieveDuplicates(arr), null, 2)}`; log.textContent += `\n\n**Looped\n${ JSON.stringify(retrieveDuplicatesLoop(arr), null, 2)}`; // reducer function retrieveDuplicates(arr) { return arr.reduce( ( acc, v, i ) => { const exists = v.include ? v : arr.slice(i+1).find( vv => v.id === vv.id && v.score === vv.score ); acc = !acc.length && exists ? acc.concat({...v}) : acc; return exists ? [...acc, {...exists}] : acc; }, [] ); } // Or in a classic loop function retrieveDuplicatesLoop(arr) { let result = []; for (let i = 0; i < arr.length; i += 1) { const exist = arr[i].include ? arr[i] : arr.slice(i+1).find(v => arr[i].id === v.id && arr[i].score === v.score); if (!result.length && exist) { result.push(arr[i]); } result = exist && result.concat(arr[i]) || result; } return result; } <pre></pre>