2015-08-27 22 views
16

Ho una matrice di oggetti che vorrei ridurre in base a una coppia specifica key:value. Voglio creare un array che include solo un oggetto per questa specifica coppia key:value. Non importa necessariamente quale oggetto dei duplicati viene copiato nel nuovo array.JavaScript: Rimuovere i duplicati di oggetti che condividono lo stesso valore di proprietà

Ad esempio, voglio tagliare in base alla price proprietà di arrayWithDuplicates, la creazione di un nuovo array che include solo una delle ogni valore:

var arrayWithDuplicates = [ 
    {"color":"red", 
    "size": "small", 
    "custom": { 
     "inStock": true, 
     "price": 10 
    } 
    }, 
    {"color":"green", 
    "size": "small", 
    "custom": { 
     "inStock": true, 
     "price": 30 
    } 
    }, 
    {"color":"blue", 
    "size": "medium", 
    "custom": { 
     "inStock": true, 
     "price": 30 
    } 
    }, 
    {"color":"red", 
    "size": "large", 
    "custom": { 
     "inStock": true, 
     "price": 20 
    } 
    } 
]; 

diventerebbero:

var trimmedArray = [ 
    {"color":"red", 
    "size": "small", 
    "custom": { 
     "inStock": true, 
     "price": 10 
    } 
    }, 
    {"color":"green", 
    "size": "small", 
    "custom": { 
     "inStock": true, 
     "price": 30 
    } 
    }, 
    {"color":"red", 
    "size": "large", 
    "custom": { 
     "inStock": true, 
     "price": 20 
    } 
    } 
]; 

C'è una funzione JavaScript o angolare che passerebbe in loop e fare questo?

MODIFICA: la proprietà da filtrare è nidificata in un'altra proprietà.

+0

possibile duplicato di [Rimuovi duplicati da un array di oggetti in JavaScript] (http://stackoverflow.com/questions/2218999/remove-duplicates-from-an-array-of-objects-in-javascript) –

+0

stai cercando qualcosa come _.map o _.pluck function in underscor e? http://underscorejs.org/#pluck – ncubica

risposta

1

È possibile utilizzare underscore per questo:

//by size: 
var uSize = _.uniq(arrayWithDuplicates, function(p){ return p.size; }); 

//by custom.price; 
var uPrice = _.uniq(arrayWithDuplicates, function(p){ return p.custom.price; }); 
+0

È stato modificato in _.uniqBy e ottiene il nome di proprietà 'univoco'. _.uniqBy ([{'x': 1}, {'x': 2}, {'x': 1}], 'x'); // => [{'x': 1}, {'x': 2}] – natansun

7

Io non credo che ci sia una funzione built-in in angolare, ma non è difficile creare uno:

function removeDuplicates(originalArray, objKey) { 
    var trimmedArray = []; 
    var values = []; 
    var value; 

    for(var i = 0; i < originalArray.length; i++) { 
    value = originalArray[i][objKey]; 

    if(values.indexOf(value) === -1) { 
     trimmedArray.push(originalArray[i]); 
     values.push(value); 
    } 
    } 

    return trimmedArray; 

} 

utilizzo:

removeDuplicates(arrayWithDuplicates, 'size'); 

Returns:

[ 
    { 
     "color": "red", 
     "size": "small" 
    }, 
    { 
     "color": "blue", 
     "size": "medium" 
    }, 
    { 
     "color": "red", 
     "size": "large" 
    } 
] 

E

removeDuplicates(arrayWithDuplicates, 'color'); 

Returns:

[ 
    { 
     "color": "red", 
     "size": "small" 
    }, 
    { 
     "color": "green", 
     "size": "small" 
    }, 
    { 
     "color": "blue", 
     "size": "medium" 
    } 
] 
17
function removeDuplicatesBy(keyFn, array) { 
    var mySet = new Set(); 
    return array.filter(function(x) { 
    var key = keyFn(x), isNew = !mySet.has(key); 
    if (isNew) mySet.add(key); 
    return isNew; 
    }); 
} 

di utilizzo (funzioni di direzione EcmaScript6 lo rende un aspetto migliore):

removeDuplicatesBy(x => x.custom.price, yourArrayWithDuplicates); 

EDIT: a cura frammento di non utilizzare il nome della proprietà, ma da usare una funzione di selezione chiave, in modo da poter raggiungere proprietà nidificate.

+0

Grazie! Questo ha sicuramente funzionato, ma ho appena modificato la mia domanda per riflettere sul fatto che questo ha bisogno di filtrare le proprietà annidate (enorme mancanza da parte mia). La tua funzione potrebbe gestirlo? –

+0

ha modificato la mia risposta –

+0

Grazie, buona risposta, ma ovviamente se si utilizza ES6 si potrebbe incorrere in problemi nei browser più vecchi senza una sorta di shim o polyfill (che non è possibile per l'operatore della freccia per quanto ne so dato che si tratta di un errore di sintassi). Per farlo funzionare con browser antichi come IE11 basta usare la funzione: 'removeDuplicatesBy (function (x) {return x.custom.price;}, yourArrayWithDuplicates);' – nothingisnecessary

5

Utilizzare Array.filter(), tenere traccia dei valori utilizzando un Object come hash e filtrare tutti gli elementi il ​​cui valore è già contenuto nell'hash.

function trim(arr, key) { 
    var values = {}; 
    return arr.filter(function(item){ 
     var val = item[key]; 
     var exists = values[val]; 
     values[val] = true; 
     return !exists; 
    }); 
} 
+0

grazie mille, mi ha salvato molto !!! – blackend

0

Fuori della parte superiore della mia testa non c'è una funzione che farà questo per voi come avete a che fare con una serie di oggetti e anche non c'è una regola per cui duplicato sarebbe stato rimosso come duplicato.

Nel tuo esempio rimuovi quello con size: small ma se dovessi implementarlo utilizzando un ciclo probabilmente includeresti il ​​primo ed escluderei l'ultimo mentre fai un ciclo attraverso l'array.

Può valere la pena dare un'occhiata a una libreria come lodash e creare una funzione che utilizza una combinazione dei suoi metodi API per ottenere il comportamento desiderato desiderato.

Ecco una possibile soluzione che è possibile utilizzare facendo uso di matrici di base e un'espressione di filtro per verificare se un nuovo elemento sarebbe considerato un duplicato prima di essere collegato a un risultato di ritorno.

var arrayWithDuplicates = [ 
    {"color":"red", "size": "small"}, 
    {"color":"green", "size": "small"}, 
    {"color":"blue", "size": "medium"}, 
    {"color":"red", "size": "large"} 
]; 

var reduce = function(arr, prop) { 
    var result = [], 
     filterVal, 
     filters, 
     filterByVal = function(n) { 
      if (n[prop] === filterVal) return true; 
     }; 
    for (var i = 0; i < arr.length; i++) { 
     filterVal = arr[i][prop]; 
     filters = result.filter(filterByVal); 
     if (filters.length === 0) result.push(arr[i]); 
    } 
    return result; 
}; 

console.info(reduce(arrayWithDuplicates, 'color')); 

È possibile controllare alcuni letteratura sulla Array filtraggio here Se è necessario fornire una preferenza su quale elemento da rimuovere è possibile definire parametri extra e la logica che renderanno i controlli di proprietà in più prima di aggiungere ad un valore di ritorno.

Spero che questo aiuti!

1

Soluzione semplice, anche se non il più performante:

var unique = []; 
duplicates.forEach(function(d) { 
    var found = false; 
    unique.forEach(function(u) { 
     if(u.key == d.key) { 
      found = true; 
     } 
    }); 
    if(!found) { 
     unique.push(d); 
    } 
}); 
1

utilizzando lodash è possibile filtrare fuori facilmente

il primo parametro sarà il tuo array e il secondo sarà il tuo campo con i duplicati

_.uniqBy(arrayWithDuplicates, 'color') 

che restituisce un array con valore unico

0

Ecco il modo in cui dattiloscritto

public removeDuplicates(originalArray:any[], prop) { 
    let newArray = []; 
    let lookupObject = {}; 

    originalArray.forEach((item, index) => { 
     lookupObject[originalArray[index][prop]] = originalArray[index]; 
    }); 

    Object.keys(lookupObject).forEach(element => { 
     newArray.push(lookupObject[element]); 
    }); 
    return newArray; 
} 

E

let output = this.removeDuplicates(yourArray,'color'); 
Problemi correlati