2015-06-09 24 views
20

Ho bisogno di aiuto con l'iterazione attraverso l'array, continuo a rimanere bloccato oa reinventare la ruota.Come posso verificare se la matrice di oggetti ha valori di proprietà duplicati?

values = [ 
    { name: 'someName1' }, 
    { name: 'someName2' }, 
    { name: 'someName1' }, 
    { name: 'someName1' } 
] 

Come potrei controllare se ci sono due (o più) stesso valore del nome in ordine? Non ho bisogno di un contatore, semplicemente impostando alcune variabili se i valori dell'array non sono univoci. Tieni presente che la lunghezza dell'array è dinamica, anche i valori dell'array.

+0

@AmiTavory C'è almeno una chiara differenza: la domanda esamina una matrice di primitivi ('arr = [9, 9, 9, 111, 2, 3, 3, 4, 4, 5, 7];), e guarda alla deduplicazione in base alle proprietà degli oggetti. Semantico, forse, ma le due risposte più votate non riguardano esattamente questo caso. '/ giphy più ne sai (mi rendo conto che non farò nulla) – ruffin

+0

@ruffin Punto preso. Commento rimosso –

risposta

37

Usa array.prototype.map e array.prototype.some:

var values = [ 
    { name: 'someName1' }, 
    { name: 'someName2' }, 
    { name: 'someName4' }, 
    { name: 'someName2' } 
]; 

var valueArr = values.map(function(item){ return item.name }); 
var isDuplicate = valueArr.some(function(item, idx){ 
    return valueArr.indexOf(item) != idx 
}); 
console.log(isDuplicate); 

JSFIDDLE.

+2

'indexOf' darà prestazioni pessime, se la matrice è grande. – thefourtheye

+5

Sostituirò la parte restituita con: valore restituitoArr.indexOf (elemento, idx + 1)! == -1 –

+0

Molto utile ... Grazie –

22

ECMA Script 6 Versione

Se ci si trova in un ambiente che supporta ECMA Script 6 di Set, quindi è possibile utilizzare Array.prototype.some e un oggetto Set, come questo

let seen = new Set(); 
var hasDuplicates = values.some(function(currentObject) { 
    return seen.size === seen.add(currentObject.name).size; 
}); 

Qui, inseriamo name di ogni oggetto nel Set e controlliamo se lo size prima e dopo l'aggiunta sono uguali. Funziona perché Set.size restituisce un numero basato su dati univoci (imposta solo aggiunge voci se i dati sono univoci). Se/quando hai nomi duplicati, le dimensioni non aumenteranno (perché i dati non saranno univoci), il che significa che avremmo già visto il nome corrente e restituirà true.


ECMA Script 5 Versione

Se non si dispone di Set supporto, quindi è possibile utilizzare un oggetto JavaScript normale per sé, come questo

var seen = {}; 
var hasDuplicates = values.some(function(currentObject) { 

    if (seen.hasOwnProperty(currentObject.name)) { 
     // Current name is already seen 
     return true; 
    } 

    // Current name is being seen for the first time 
    return (seen[currentObject.name] = false); 
}); 

Lo stesso può essere scritta succintamente, come questo

var seen = {}; 
var hasDuplicates = values.some(function (currentObject) { 
    return seen.hasOwnProperty(currentObject.name) 
     || (seen[currentObject.name] = false); 
}); 

Nota: In entrambi i casi, viene utilizzato Array.prototype.some perché si verificherà un cortocircuito. Nel momento in cui ottiene un valore di verità dalla funzione, restituirà immediatamente true, non elaborerà il resto degli elementi.

+0

Approccio interessante, usando 'hasOwnProperty'. Ho visto in poche altre risposte che hai commentato che 'indexOf' avrà scarse prestazioni in grandi array. Il metodo ES5 sopra suggerito è più adatto alle prestazioni in generale per oggetti più grandi? –

+0

@JoshBeam 'indexOf' dovrà iterare la matrice per scoprire se l'elemento è presente oppure no, ma tutto ciò che utilizza l'hashing sarà molto più veloce. Quindi, entrambi i modi ES5 e ES6 saranno molto più veloci se l'array è abbastanza grande. – thefourtheye

+0

Come posso essere sicuro, elaborerà il resto degli elementi? –

0

È possibile utilizzare map per restituire solo il nome, e quindi utilizzare questo forEach trucco per verificare se esiste almeno due volte:

var areAnyDuplicates = false; 

values.map(function(obj) { 
    return obj.name; 
}).forEach(function (element, index, arr) { 
    if (arr.indexOf(element) !== index) { 
     areAnyDuplicates = true; 
    } 
}); 

Fiddle

+0

'indexOf' darà prestazioni pessime, se l'array è grande. – thefourtheye

1

Con Underscore.js È possibile eseguire alcune operazioni con Underscore. Ecco uno di loro. Verifica se l'array è già univoco.

function isNameUnique(values){ 
    return _.uniq(values, function(v){ return v.name }).length == values.length 
} 

con vaniglia JavaScript controllando se ci sono nomi ricorrenti nella matrice.

function isNameUnique(values){ 
    var names = values.map(function(v){ return v.name }); 
    return !names.some(function(v){ 
     return names.filter(function(w){ return w==v }).length>1 
    }); 
} 
2

Provare un semplice ciclo:

var repeat = [], tmp, i = 0; 

while(i < values.length){ 
    repeat.indexOf(tmp = values[i++].name) > -1 ? values.pop(i--) : repeat.push(tmp) 
} 

Demo

+0

Questo termina semplicemente con un array di de-duplicazione di essi. – spartikus

0

sapere se semplice array ha duplicati possiamo confrontare primi e ultimi indici dello stesso valore :

La funzione:

var hasDupsSimple = function(array) { 

    return array.some(function(value) {       // .some will break as soon as duplicate found (no need to itterate over all array) 
     return array.indexOf(value) !== array.lastIndexOf(value); // comparing first and last indexes of the same value 
    }) 
} 

Test:

hasDupsSimple([1,2,3,4,2,7]) 
// => true 

hasDupsSimple([1,2,3,4,8,7]) 
// => false 

hasDupsSimple([1,"hello",3,"bye","hello",7]) 
// => true 

Per un array di oggetti è necessario convertire i valori oggetti per un semplice array primo:

Converting matrice di oggetti per l'array semplice con map:

var hasDupsObjects = function(array) { 

    return array.map(function(value) { 
    return value.suit + value.rank 

    }).some(function(value, index, array) { 
     return array.indexOf(value) !== array.lastIndexOf(value); 
    }) 
} 

Test:

var cardHand = [ 
    { "suit":"spades", "rank":"ten" }, 
    { "suit":"diamonds", "rank":"ace" }, 
    { "suit":"hearts", "rank":"ten" }, 
    { "suit":"clubs", "rank":"two" }, 
    { "suit":"spades", "rank":"three" }, 
] 

hasDupsObjects(cardHand); 
// => false 

var cardHand2 = [ 
    { "suit":"spades", "rank":"ten" }, 
    { "suit":"diamonds", "rank":"ace" }, 
    { "suit":"hearts", "rank":"ten" }, 
    { "suit":"clubs", "rank":"two" }, 
    { "suit":"spades", "rank":"ten" }, 
] 

hasDupsObjects(cardHand2); 
// => true 
0

se siete alla ricerca di un valore booleano, il modo più rapido sarebbe

var values = [ 
 
    { name: 'someName1' }, 
 
    { name: 'someName2' }, 
 
    { name: 'someName1' }, 
 
    { name: 'someName1' } 
 
] 
 

 
// solution 
 
var hasDuplicate = false; 
 
values.map(v => v.name).sort().sort((a, b) => { 
 
    if (a === b) hasDuplicate = true 
 
}) 
 
console.log('hasDuplicate', hasDuplicate)