Wie kann ich überprüfen, ob das Array von Objekten doppelte Eigenschaftswerte aufweist?

73

Ich brauche Hilfe beim Durchlaufen des Arrays, stecke immer wieder fest oder erfinde das Rad neu.

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

Wie kann ich überprüfen, ob das Array zwei (oder mehr) gleiche Namenswerte enthält? Ich brauche keinen Zähler, sondern setze nur eine Variable, wenn die Array-Werte nicht eindeutig sind. Beachten Sie, dass die Array-Länge dynamisch ist, auch die Array-Werte.

kodifiziert werden
quelle
@AmiTavory Es gibt mindestens einen deutlichen Unterschied: arr = [9, 9, 9, 111, 2, 3, 3, 3, 4, 4, 5, 7];Diese Frage befasst sich mit einer Reihe von Grundelementen ( ), und dies betrifft die Dedupierung basierend auf den Eigenschaften von Objekten. Vielleicht semantisch, aber die beiden Antworten mit den höchsten Stimmen sprechen diesen Fall nicht genau an. /giphy the more you know(Mir ist klar, dass das nichts bringt)
Ruffin
@ Ruffin Punkt genommen. Kommentar entfernt.
Ami Tavory

Antworten:

83

Verwenden Sie array.prototype.map und 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.

Amir Popovich
quelle
3
indexOfwird sehr schlechte Leistung geben, wenn das Array groß ist.
thefourtheye
9
Ich werde den Rückgabeteil ersetzen durch: RückgabewertArr.indexOf (item, idx + 1)! == -1
Grégory NEUT
56

ECMA Script 6 Version

Wenn Sie sich in einer Umgebung befinden, die ECMA Script 6 unterstützt Set, können Sie Array.prototype.someein SetObjekt wie dieses verwenden

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

Hier fügen wir jedes einzelne Objekt namein das ein Setund prüfen, ob die sizevor und nach dem Hinzufügen gleich sind. Dies funktioniert, weil Set.sizeeine Nummer basierend auf eindeutigen Daten zurückgegeben wird (set fügt nur Einträge hinzu, wenn die Daten eindeutig sind). Wenn Sie doppelte Namen haben, wird die Größe nicht erhöht (da die Daten nicht eindeutig sind), was bedeutet, dass wir den aktuellen Namen bereits gesehen haben und er true zurückgibt.


ECMA Script 5 Version

Wenn Sie keine SetUnterstützung haben, können Sie ein normales JavaScript-Objekt wie dieses verwenden

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);
});

Das gleiche kann so kurz und bündig geschrieben werden

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

Hinweis: In beiden Fällen verwenden wir, Array.prototype.someweil es kurzschließen wird. Sobald die Funktion einen wahrheitsgemäßen Wert erhält, kehrt sie truesofort zurück und verarbeitet die restlichen Elemente nicht.

thefourtheye
quelle
Interessanter Ansatz mit hasOwnProperty. Ich habe in einigen anderen Antworten gesehen, die Sie kommentiert indexOfhaben und die in großen Arrays eine schlechte Leistung haben werden. Ist die oben beschriebene ES5-Methode, die Sie vorgeschlagen haben, für größere Objekte im Allgemeinen leistungsfreundlicher?
Josh Beam
@JoshBeam indexOfmuss das Array iterieren, um herauszufinden, ob das Element vorhanden ist oder nicht, aber alles, was Hashing verwendet, ist viel schneller. Wenn das Array ziemlich groß ist, sind sowohl die ES5- als auch die ES6-Methode viel schneller.
thefourtheye
Wie kann ich sicherstellen, dass der Rest der Elemente verarbeitet wird?
Anna Smother
@AnnaSmother Wenn Sie alle Elemente verarbeiten möchten, verwenden forEachund schreiben Sie die Logik selbst.
thefourtheye
1
@chovy Die Frage lautet: "Wie kann ich überprüfen, ob zwei (oder mehr) gleiche Namenswerte im Array vorhanden sind? Ich benötige keinen Zähler, sondern setze nur eine Variable, wenn die Array-Werte nicht eindeutig sind." Das hat nichts mit dem Entfernen der Duplikate zu tun. Ich denke das ist die beste Antwort hier!
Calcazar
7

In TS und ES6 können Sie ein neues Set mit der Eigenschaft erstellen, dass es eindeutig ist, und seine Größe mit dem ursprünglichen Array vergleichen.

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

const uniqueValues = new Set(values.map(v => v.name));

if (uniqueValues.size < values.length) {
  console.log('duplicates found')
}

lukas_o
quelle
3

Um zu wissen, ob ein einfaches Array Duplikate enthält, können wir den ersten und den letzten Index mit demselben Wert vergleichen:

Die Funktion:

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
    })
}

Tests:

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

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

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

Für ein Array von Objekten müssen wir zuerst die Objektwerte in ein einfaches Array konvertieren:

Konvertieren eines Array von Objekten in ein einfaches Array mit 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);  
     })
}

Tests:

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
System-Neustart
quelle
Wie finde
ich
3

Wenn Sie nach einem Booleschen Wert suchen, ist der schnellste Weg

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)

user2167582
quelle
2

Mit Underscore.js Mit Underscore gibt es einige Möglichkeiten. Hier ist einer von ihnen. Überprüfen, ob das Array bereits eindeutig ist.

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

Mit Vanille-JavaScript Überprüfen Sie, ob das Array keine wiederkehrenden Namen enthält.

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 
    });
}
TaoPR
quelle
2

Versuchen Sie eine einfache Schleife:

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

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

Demo

Walter Chapilliquen - wZVanG
quelle
Dies endet nur mit einem de-duped Array von ihnen.
Spartikus
1

Mit können Sie mapnur den Namen zurückgeben und dann mit diesem forEachTrick überprüfen, ob er mindestens zweimal vorhanden ist:

var areAnyDuplicates = false;

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

Geige

Omri Aharon
quelle
indexOfwird sehr schlechte Leistung geben, wenn das Array groß ist.
thefourtheye
1
//checking duplicate elements in an array
var arr=[1,3,4,6,8,9,1,3,4,7];
var hp=new Map();
console.log(arr.sort());
var freq=0;
for(var i=1;i<arr.length;i++){
// console.log(arr[i-1]+" "+arr[i]);
if(arr[i]==arr[i-1]){
freq++;

}
else{
hp.set(arr[i-1],freq+1);
freq=0;
}
}
console.log(hp);
Ravi
quelle
Kopieren und Einfügen von mit Knoten scriptname.js laufen
Ravi