Ich habe eine Reihe von Zahlen, die ich sicherstellen muss, um eindeutig zu sein. Ich habe das Code-Snippet unten im Internet gefunden und es funktioniert gut, bis das Array eine Null enthält. Ich habe dieses andere Skript hier auf SO gefunden, das fast genau so aussieht, aber es scheitert nicht.
Kann mir jemand helfen zu lernen, wo das Prototyp-Skript schief geht?
Array.prototype.getUnique = function() {
var o = {}, a = [], i, e;
for (i = 0; e = this[i]; i++) {o[e] = 1};
for (e in o) {a.Push (e)};
return a;
}
Mit JavaScript 1.6/ECMAScript 5 können Sie die native filter
-Methode eines Arrays folgendermaßen verwenden, um ein Array mit eindeutigen Werten zu erhalten:
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
// usage example:
var a = ['a', 1, 'a', 2, '1'];
var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']
Die native Methode filter
durchläuft das Array und hinterlässt nur die Einträge, die die angegebene Callback-Funktion onlyUnique
übergeben.
onlyUnique
prüft, ob der angegebene Wert der erste ist. Wenn nicht, muss es ein Duplikat sein und wird nicht kopiert.
Diese Lösung funktioniert ohne zusätzliche Bibliothek wie jQuery oder prototype.js.
Es funktioniert auch für Arrays mit gemischten Werttypen.
Für alte Browser (<ie9), die die systemeigenen Methoden filter
und indexOf
nicht unterstützen, finden Sie in der MDN-Dokumentation Umgehungen für filter und indexOf .
Wenn Sie das letzte Vorkommen eines Werts beibehalten möchten, ersetzen Sie einfach indexOf
durch lastIndexOf
.
Mit ES6 könnte man es abkürzen:
// usage example:
var myArray = ['a', 1, 'a', 2, '1'];
var unique = myArray.filter((v, i, a) => a.indexOf(v) === i);
// unique is ['a', 1, 2, '1']
Danke an Camilo Martin für den Hinweis im Kommentar.
ES6 verfügt über ein natives Objekt Set
, um eindeutige Werte zu speichern. Um ein Array mit eindeutigen Werten zu erhalten, können Sie jetzt Folgendes tun:
var myArray = ['a', 1, 'a', 2, '1'];
let unique = [...new Set(myArray)];
// unique is ['a', 1, 2, '1']
Der Konstruktor von Set
nimmt ein iterierbares Objekt wie Array und der Spread-Operator ...
wandelt den Satz zurück in ein Array. Danke an Lukas Liese für den Hinweis im Kommentar.
Aktualisierte Antwort für ES6/ES2015: Bei Verwendung von Set lautet die einzeilige Lösung:
var items = [4,5,4,6,3,4,5,2,23,1,4,4,4]
var uniqueItems = Array.from(new Set(items))
Welche zurückkehrt
[4, 5, 6, 3, 2, 23, 1]
Wie le_m vorgeschlagen, kann dies auch mit spread Operator gekürzt werden
var uniqueItems = [...new Set(items)]
Sie können auch nderscore.js verwenden.
console.log(_.uniq([1, 2, 1, 3, 1, 4]));
<script src="http://underscorejs.org/underscore-min.js"></script>
was zurückkommt:
[1, 2, 3, 4]
Ich weiß, dass diese Frage bereits mehr als 30 Antworten hat. Ich habe aber zuerst alle vorhandenen Antworten durchgelesen und meine eigenen Nachforschungen angestellt.
Ich teile alle Antworten in 4 mögliche Lösungen auf:
[...new Set( [1, 1, 2] )];
{ }
, um Duplikate zu verhindern[ ]
filter + indexOf
Hier finden Sie Beispielcodes, die in Antworten gefunden wurden:
[...new Set( [1, 1, 2] )];
function uniqueArray0(array) {
var result = Array.from(new Set(array));
return result
}
{ }
, um Duplikate zu verhindernfunction uniqueArray1( ar ) {
var j = {};
ar.forEach( function(v) {
j[v+ '::' + typeof v] = v;
});
return Object.keys(j).map(function(v){
return j[v];
});
}
[ ]
function uniqueArray2(arr) {
var a = [];
for (var i=0, l=arr.length; i<l; i++)
if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
a.Push(arr[i]);
return a;
}
filter + indexOf
function uniqueArray3(a) {
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
// usage
var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']
return unique;
}
Und ich habe mich gefragt, welche schneller ist. Ich habe sample Google Sheet gemacht, um Funktionen zu testen. Hinweis: ECMA 6 ist in Google Sheets nicht verfügbar. Daher kann ich es nicht testen.
Hier ist das Ergebnis der Tests:
Ich habe erwartet, dass der Code mit dem Objekt { }
gewonnen wird, da er Hash verwendet. Daher bin ich froh, dass Tests in Chrome und IE die besten Ergebnisse für diesen Algorithmus ergeben haben. Danke an @rab für den Code .
Ich habe eine Nice-Methode gefunden, die jQuery verwendet
arr = $.grep(arr, function(v, k){
return $.inArray(v ,arr) === k;
});
Hinweis: Dieser Code wurde aus Paul Irishs Entenstichposten - Ich habe vergessen, die Anerkennung zu vergeben: P
Kürzeste Lösung mit ES6: [...new Set( [1, 1, 2] )];
Oder wenn Sie den Array-Prototyp ändern möchten (wie in der ursprünglichen Frage):
Array.prototype.getUnique = function() {
return [...new Set( [this] )];
};
EcmaScript 6 ist derzeit nur in einigen Browsern (August 2015) teilweise implementiert , aber Babel ist sehr beliebt geworden, um ES6 (und sogar ES7) wieder auf ES5 umzuwandeln. Auf diese Weise können Sie heute noch ES6-Code schreiben!
Wenn Sie sich fragen, was der ...
bedeutet, wird er als spread-Operator bezeichnet. Aus MDN : «Mit dem Spread-Operator kann ein Ausdruck an Stellen erweitert werden, an denen mehrere Argumente (für Funktionsaufrufe) oder mehrere Elemente (für Array-Literale) erwartet werden». Da ein Set ein Iterer ist (und nur eindeutige Werte haben kann), erweitert der Spread-Operator den Satz, um das Array zu füllen.
Ressourcen zum Lernen von ES6:
Einfachste Lösung:
var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log([...new Set(arr)]);
Oder:
var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log(Array.from(new Set(arr)));
Der einfachste und schnellste (in Chrome) Weg, dies zu tun:
Array.prototype.unique = function() {
var a = [];
for (var i=0, l=this.length; i<l; i++)
if (a.indexOf(this[i]) === -1)
a.Push(this[i]);
return a;
}
Führt einfach jedes Element im Array durch, prüft, ob das Element bereits in der Liste enthalten ist, und wenn nicht, drücken Sie auf das Array, das zurückgegeben wird.
Laut jsPerf ist diese Funktion die schnellste von denen, die ich überall finden könnte - Sie können jedoch gerne Ihre eigene hinzufügen.
Die Nicht-Prototyp-Version:
function uniques(arr) {
var a = [];
for (var i=0, l=arr.length; i<l; i++)
if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
a.Push(arr[i]);
return a;
}
Wenn auch das Array sortiert werden muss, ist das Folgende am schnellsten:
Array.prototype.sortUnique = function() {
this.sort();
var last_i;
for (var i=0;i<this.length;i++)
if ((last_i = this.lastIndexOf(this[i])) !== i)
this.splice(i+1, last_i-i);
return this;
}
oder Nicht-Prototyp:
function sortUnique(arr) {
arr.sort();
var last_i;
for (var i=0;i<arr.length;i++)
if ((last_i = arr.lastIndexOf(arr[i])) !== i)
arr.splice(i+1, last_i-i);
return arr;
}
Dies ist auch schneller als die obige Methode in den meisten Nicht-Chrome-Browsern.
NUR LEISTUNG! Dieser Code ist wahrscheinlich 10x schneller als alle Codes hier * funktioniert in allen Browsern und hat auch die geringste Auswirkung auf den Speicher .... und mehr
wenn Sie das alte Array nicht wiederverwenden müssen, ist es wahrscheinlich der schnellste Weg, dies zu tun, auch sehr kurz.
var array=[1,2,3,4,5,6,7,8,9,0,1,2,1];
dann kannst du das probieren
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 1];
function toUnique(a, b, c) { //array,placeholder,placeholder
b = a.length;
while (c = --b)
while (c--) a[b] !== a[c] || a.splice(c, 1);
return a // not needed ;)
}
console.log(toUnique(array));
//[3, 4, 5, 6, 7, 8, 9, 0, 2, 1]
Ich habe mir diese Funktion ausgedacht, als ich diesen Artikel gelesen habe ...
http://www.shamasis.net/2009/09/fast-algorithm-to-find-unique-items-in-javascript-array/
Ich mag die for-Schleife nicht. es hat zu viele parameter. ich mag die while-- schleife. while ist die schnellste Schleife in allen Browsern, außer der, die wir alle so sehr mögen ... chrome.
trotzdem habe ich die erste Funktion geschrieben, die while verwendet. Und yep, es ist ein bisschen schneller als die im Artikel gefundene Funktion. Aber nicht genug .unique2()
im nächsten Schritt verwende moderne js. Object.keys
Ich habe die andere for-Schleife durch die Object.keys von js1.7 ersetzt ... etwas schneller und kürzer (in chrome 2x schneller);) . Nicht genug! .unique3()
.
zu diesem Zeitpunkt dachte ich darüber nach, was ich in MEINER einzigartigen Funktion wirklich brauche. Ich brauche das alte Array nicht, ich möchte eine schnelle Funktion. Also habe ich 2 while-Schleifen + Spleiß verwendet .unique4()
Unnötig zu sagen, dass ich beeindruckt war.
chrome: Die üblichen 150.000 Operationen pro Sekunde stiegen auf 1.800.000 Operationen pro Sekunde.
ie: 80.000 op/s gegenüber 3.500.000 op/s
ios: 18.000 Operationen gegenüber 170.000 Operationen
safari: 80.000 op/s gegen 6.000.000 op/s
Beweis http://jsperf.com/wg oder besser console.time ... microtime ... was auch immer
unique5()
soll Ihnen nur zeigen, was passiert, wenn Sie das alte Array behalten möchten.
Verwenden Sie nicht Array.prototype
, Wenn Sie nicht wissen, was Sie tun. Ich habe gerade viel kopiert und vergangen. Verwenden Sie Object.defineProperty(Array.prototype,...,writable:false,enumerable:false})
, wenn Sie einen nativen Prototyp erstellen möchten. Beispiel: https://stackoverflow.com/a/20463021/24507
Demo http://jsfiddle.net/46S7g/
ANMERKUNG: Ihr altes Array wird nach dieser Operation zerstört/zu einem Unikat.
wenn Sie den obigen Code nicht lesen können, lesen Sie ein Javascript-Buch oder hier einige Erklärungen zu kürzerem Code. https://stackoverflow.com/a/21353032/24507
einige verwenden indexOf
... nicht ... http://jsperf.com/dgfgghfghfghghgfhgfhfghfhgfh
für leere Arrays
!array.length||toUnique(array);
Viele der Antworten sind für Anfänger möglicherweise nicht hilfreich. Wenn das De-Dupen eines Arrays schwierig ist, wissen sie dann wirklich etwas über die Prototypkette oder sogar über jQuery?
In modernen Browsern ist es eine saubere und einfache Lösung, Daten in einem Set zu speichern, das als Liste eindeutiger Werte konzipiert ist.
const cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
const uniqueCars = Array.from(new Set(cars));
Der Array.from
ist nützlich, um das Set zurück in ein Array zu konvertieren, sodass Sie auf alle fantastischen Methoden (Features) von Arrays zugreifen können. Es gibt auch andere Wege das Gleiche zu tun. Möglicherweise benötigen Sie Array.from
jedoch nicht, da Sets viele nützliche Funktionen wie forEach enthalten.
Wenn Sie den alten Internet Explorer unterstützen müssen und daher Set nicht verwenden können, kopieren Sie Elemente in ein neues Array, und überprüfen Sie vorher, ob sie bereits im neuen Array enthalten sind.
// Create a list of cars, with duplicates.
var cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
// Create a list of unique cars, to put a car in if we haven't already.
var uniqueCars = [];
// Go through each car, one at a time.
cars.forEach(function (car) {
// The code within the following block runs only if the
// current car does NOT exist in the uniqueCars list
// - a.k.a. prevent duplicates
if (uniqueCars.indexOf(car) === -1) {
// Since we now know we haven't seen this car before,
// copy it to the end of the uniqueCars list.
uniqueCars.Push(car);
}
});
Um dies sofort wiederverwendbar zu machen, setzen wir es in eine Funktion.
function deduplicate(data) {
if (data.length > 0) {
var result = [];
data.forEach(function (elem) {
if (result.indexOf(elem) === -1) {
result.Push(elem);
}
});
return result;
}
}
Um die Duplikate loszuwerden, würden wir das jetzt tun.
var uniqueCars = deduplicate(cars);
Der deduplicate(cars)
-Teil wird zu der Sache, die wir Ergebnis genannt haben, wenn die Funktion abgeschlossen ist.
Geben Sie einfach den Namen eines beliebigen Arrays an.
["Defects", "Total", "Days", "City", "Defects"].reduce(function(prev, cur) {
return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
}, []);
[0,1,2,0,3,2,1,5].reduce(function(prev, cur) {
return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
}, []);
Dieser Prototyp getUnique
ist nicht völlig korrekt, denn wenn ich ein Array wie: ["1",1,2,3,4,1,"foo"]
habe, wird ["1","2","3","4"]
zurückgegeben und "1"
ist string und 1
ist eine ganze Zahl. Sie sind anders.
Hier ist eine richtige Lösung:
Array.prototype.unique = function(a){
return function(){ return this.filter(a) }
}(function(a,b,c){ return c.indexOf(a,b+1) < 0 });
mit:
var foo;
foo = ["1",1,2,3,4,1,"foo"];
foo.unique();
Das obige wird ["1",2,3,4,1,"foo"]
erzeugen.
Wir können dies mit ES6-Sets tun:
var duplicatedArray = [1,2,3,4,5,1,1,1,2,3,4];
var uniqueArray = Array.from(new Set(duplicatedArray));
// Die Ausgabe wird sein
uniqueArray = [1,2,3,4,5];
Ohne die Erweiterung von Array.prototype (dies soll eine schlechte Praxis sein) oder die Verwendung von Jquery/Unterstrich, können Sie das Array einfach filter
verwenden.
Beim letzten Auftreten halten:
function arrayLastUnique(array) {
return array.filter(function (a, b, c) {
// keeps last occurrence
return c.indexOf(a, b + 1) < 0;
});
},
oder erstes Auftreten:
function arrayFirstUnique(array) {
return array.filter(function (a, b, c) {
// keeps first occurrence
return c.indexOf(a) === b;
});
},
Nun, es ist nur Javascript ECMAScript 5+, was nur IE9 + bedeutet, aber es ist Nizza für eine Entwicklung in nativem HTML/JS (Windows Store App, Firefox OS, Sencha, Phonegap, Titanium, ...).
Das liegt daran, dass 0
in JavaScript ein falscher Wert ist.
this[i]
ist falsch, wenn der Wert des Arrays 0 oder ein anderer falscher Wert ist.
Wenn Sie das Prototype-Framework verwenden, müssen Sie keine for-Schleifen ausführen. Sie können http://www.prototypejs.org/api/array/uniq wie folgt verwenden:
var a = Array.uniq();
Dadurch wird ein doppeltes Array ohne Duplikate erzeugt. Ich bin auf Ihre Frage gestoßen, als ich nach einer Methode suchte, um verschiedene Array-Datensätze zu zählen
uniq ()
Ich benutzte
größe()
und es war mein einfaches Ergebnis. p. Entschuldigung, wenn ich etwas falsch geschrieben habe
bearbeiten: Wenn Sie undefinierte Datensätze mit einem Escape-Befehl versehen möchten, können Sie sie hinzufügen
kompakt()
vorher wie folgt:
var a = Array.compact().uniq();
Array.prototype.getUnique = function() {
var o = {}, a = []
for (var i = 0; i < this.length; i++) o[this[i]] = 1
for (var e in o) a.Push(e)
return a
}
seltsam, dies wurde zuvor nicht vorgeschlagen. Um Duplikate mit dem Objektschlüssel (id
unten) in einem Array zu entfernen, können Sie Folgendes tun:
const uniqArray = array.filter((obj, idx, arr) => (
arr.findIndex((o) => o.id === obj.id) === idx
))
Ich bin nicht sicher, warum Gabriel Silveira die Funktion so geschrieben hat, aber eine einfachere Form, die für mich genauso gut und ohne die Minifikation funktioniert, ist:
Array.prototype.unique = function() {
return this.filter(function(value, index, array) {
return array.indexOf(value, index + 1) < 0;
});
};
oder in CoffeeScript:
Array.prototype.unique = ->
this.filter( (value, index, array) ->
array.indexOf(value, index + 1) < 0
)
Suche nach eindeutigen Array-Werten in einer einfachen Methode
function arrUnique(a){
var t = [];
for(var x = 0; x < a.length; x++){
if(t.indexOf(a[x]) == -1)t.Push(a[x]);
}
return t;
}
arrUnique([1,4,2,7,1,5,9,2,4,7,2]) // [1, 4, 2, 7, 5, 9]
Von Shamasis Bhattacharya 's Blog (O (2n) Zeit Komplexität):
Array.prototype.unique = function() {
var o = {}, i, l = this.length, r = [];
for(i=0; i<l;i+=1) o[this[i]] = this[i];
for(i in o) r.Push(o[i]);
return r;
};
Aus dem Blog von Paul Irish : Verbesserung von JQuery .unique()
:
(function($){
var _old = $.unique;
$.unique = function(arr){
// do the default behavior only if we got an array of elements
if (!!arr[0].nodeType){
return _old.apply(this,arguments);
} else {
// reduce the array to contain no dupes via grep/inArray
return $.grep(arr,function(v,k){
return $.inArray(v,arr) === k;
});
}
};
})(jQuery);
// in use..
var arr = ['first',7,true,2,7,true,'last','last'];
$.unique(arr); // ["first", 7, true, 2, "last"]
var arr = [1,2,3,4,5,4,3,2,1];
$.unique(arr); // [1, 2, 3, 4, 5]
Um das Problem anders anzugehen, kann es sinnvoll sein, während des Ladens des Arrays kein Duplikat zu verwenden, wie es von Set object getan wird, aber es ist noch nicht in allen Browsern verfügbar. Es spart Speicher und ist effizienter, wenn Sie den Inhalt oft überprüfen müssen.
Array.prototype.add = function (elem) {
if (this.indexOf(elem) == -1) {
this.Push(elem);
}
}
Probe:
set = [];
[1,3,4,1,2,1,3,3,4,1].forEach(function(x) { set.add(x); });
Gibt dir set = [1,3,4,2]
a.filter(( t={}, e=>!(t[e]=e in t) ))
O(n)Leistung ; Wir gehen davon aus, dass sich Ihr Array in a
befindet. Erklärung hier (+ Jeppe Verbesserung)
var a1 = [5,6,0,4,9,2,3,5,0,3,4,1,5,4,9];
var a2 = [[2, 17], [2, 17], [2, 17], [1, 12], [5, 9], [1, 12], [6, 2], [1, 12]];
var a3 = ['Mike', 'Adam','Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'];
let nd = (a) => a.filter((t={},e=>!(t[e]=e in t)))
// print
let c= x => console.log(JSON.stringify(x));
c( nd(a1) );
c( nd(a2) );
c( nd(a3) );
Ich fand, dass das Serialisieren ihres Hash-Schlüssels mir half, diese Funktion für Objekte zu nutzen.
Array.prototype.getUnique = function() {
var hash = {}, result = [], key;
for ( var i = 0, l = this.length; i < l; ++i ) {
key = JSON.stringify(this[i]);
if ( !hash.hasOwnProperty(key) ) {
hash[key] = true;
result.Push(this[i]);
}
}
return result;
}
Wenn jemand knockoutjs benutzt
ko.utils.arrayGetDistinctValues()
Übrigens haben Sie sich alle ko.utils.array*
-Dienstprogramme angesehen.
Wenn Sie mit zusätzlichen Abhängigkeiten zufrieden sind oder bereits über eine der Bibliotheken in Ihrer Codebase verfügen, können Sie Duplikate mithilfe von LoDash (oder Underscore) aus einem Array entfernen.
Verwendungszweck
Wenn Sie es noch nicht in Ihrer Codebase haben, installieren Sie es mit npm:
npm install lodash
Dann verwenden Sie es wie folgt:
import _ from 'lodash';
let idArray = _.uniq ([
1,
2,
3,
3,
3
]);
console.dir(idArray);
Aus:
[ 1, 2, 3 ]
Sie können auch sugar.js verwenden:
[1,2,2,3,1].unique() // => [1,2,3]
[{id:5, name:"Jay"}, {id:6, name:"Jay"}, {id: 5, name:"Jay"}].unique('id')
// => [{id:5, name:"Jay"}, {id:6, name:"Jay"}]
var arr = [2,3,4,2,3,4,2];
const result = [...new Set(arr)];
console.log(result);
Schau dir das an. Jquery bietet die uniq-Methode: https://api.jquery.com/jQuery.unique/
var ids_array = []
$.each($(my_elements), function(index, el) {
var id = $(this).attr("id")
ids_array.Push(id)
});
var clean_ids_array = jQuery.unique(ids_array)
$.each(clean_ids_array, function(index, id) {
elment = $("#" + id) // my uniq element
// TODO WITH MY ELEMENT
});
Ich habe Objektschlüssel verwendet, um ein eindeutiges Array zu erstellen. Ich habe folgendes versucht
function uniqueArray( ar ) {
var j = {};
ar.forEach( function(v) {
j[v+ '::' + typeof v] = v;
});
return Object.keys(j).map(function(v){
return j[v];
});
}
uniqueArray(["1",1,2,3,4,1,"foo", false, false, null,1]);
Welche gibt ["1", 1, 2, 3, 4, "foo", false, null]
zurück
Ich denke, dies ist der einfachste Weg, um einen einzigartigen Gegenstand aus einem Array zu erhalten.
var arr = [1,2,4,1,4];
arr = Array.from(new Set(arr))
console.log(arr)
Wenn Sie die mächtige Methode verkleinern zur Verfügung haben ( ≥ 5.1 ), können Sie Folgendes versuchen:
Array.prototype.uniq = function() {
return this.reduce(function(sofar, cur) {
return sofar.indexOf(cur) < 0 ? sofar.concat([cur]) : sofar;
}, []);
};
Dies ist nicht die effizienteste Implementierung (aufgrund der indexOf
-Prüfung, die im schlimmsten Fall die gesamte Liste durchgehen kann). Wenn es auf Effizienz ankommt, können Sie den "Verlauf" von Ereignissen in einer beliebigen Struktur mit wahlfreiem Zugriff (beispielsweise {}
) beibehalten und stattdessen diese eingeben. Das ist im Grunde das, was die most most answer tut, also schauen Sie sich das als Beispiel an.
[...new Set(duplicates)]
Dies ist die einfachste Methode, auf die in MDN Web Docs verwiesen wird.
const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)]) // [2, 3, 4, 5, 6, 7, 32]
Das wird funktionieren.
function getUnique(a) {
var b = [a[0]], i, j, tmp;
for (i = 1; i < a.length; i++) {
tmp = 1;
for (j = 0; j < b.length; j++) {
if (a[i] == b[j]) {
tmp = 0;
break;
}
}
if (tmp) {
b.Push(a[i]);
}
}
return b;
}
Tun Sie es mit lodash und der Lambda-Identitätsfunktion, definieren Sie es einfach, bevor Sie Ihr Objekt verwenden
const _ = require('lodash');
...
_.uniqBy([{a:1,b:2},{a:1,b:2},{a:1,b:3}], v=>v.a.toString()+v.b.toString())
_.uniq([1,2,3,3,'a','a','x'])
und haben:
[{a:1,b:2},{a:1,b:3}]
[1,2,3,'a','x']
(dies ist der einfachste Weg)
Aufbauend auf anderen Antworten, folgt hier eine weitere Variante, die ein optionales Flag zur Auswahl einer Strategie erfordert (erstes Auftreten beibehalten oder zuletzt halten):
Ohne Erweiterung Array.prototype
function unique(arr, keepLast) {
return arr.filter(function (value, index, array) {
return keepLast ? array.indexOf(value, index + 1) < 0 : array.indexOf(value) === index;
});
};
// Usage
unique(['a', 1, 2, '1', 1, 3, 2, 6]); // -> ['a', 1, 2, '1', 3, 6]
unique(['a', 1, 2, '1', 1, 3, 2, 6], true); // -> ['a', '1', 1, 3, 2, 6]
Erweitern Array.prototype
Array.prototype.unique = function (keepLast) {
return this.filter(function (value, index, array) {
return keepLast ? array.indexOf(value, index + 1) < 0 : array.indexOf(value) === index;
});
};
// Usage
['a', 1, 2, '1', 1, 3, 2, 6].unique(); // -> ['a', 1, 2, '1', 3, 6]
['a', 1, 2, '1', 1, 3, 2, 6].unique(true); // -> ['a', '1', 1, 3, 2, 6]
Sie können auch jQuery verwenden
var a = [1,5,1,6,4,5,2,5,4,3,1,2,6,6,3,3,2,4];
// note: jQuery's filter params are opposite of javascript's native implementation :(
var unique = $.makeArray($(a).filter(function(i,itm){
// note: 'index', not 'indexOf'
return i == $(a).index(itm);
}));
// unique: [1, 5, 6, 4, 2, 3]
Ursprünglich beantwortet unter: jQuery-Funktion, um alle eindeutigen Elemente aus einem Array zu erhalten
Für die Deduplizierung ist normalerweise ein Gleichheitsoperator für den angegebenen Typ erforderlich. Die Verwendung einer eq
-Funktion hindert uns jedoch daran, eine Set
zur effizienten Ermittlung von Duplikaten zu verwenden, da Set
auf ===
zurückfällt. Wie Sie sicher wissen, funktioniert ===
nicht für Referenztypen. Also sind wir nett, wenn wir nicht weiterkommen, oder?
Der Ausweg besteht einfach darin, eine Transformatorfunktion zu verwenden, mit der wir einen (Referenz-) Typ in etwas verwandeln können, das wir tatsächlich mit einem Set
nachschlagen können. Wir könnten zum Beispiel eine Hash-Funktion oder JSON.stringify
die Datenstruktur verwenden, wenn sie keine Funktionen enthält.
Oft müssen wir nur auf eine Eigenschaft zugreifen, die wir dann anstelle der Referenz von Object
vergleichen können.
Hier sind zwei Kombinatoren, die diese Anforderungen erfüllen:
const dedupeOn = k => xs => {
const s = new Set();
return xs.filter(o =>
s.has(o[k])
? null
: (s.add(o[k]), o[k]));
};
const dedupeBy = f => xs => {
const s = new Set();
return xs.filter(x => {
const r = f(x);
return s.has(r)
? null
: (s.add(r), x);
});
};
const xs = [{foo: "a"}, {foo: "b"}, {foo: "A"}, {foo: "b"}, {foo: "c"}];
console.log(
dedupeOn("foo") (xs)); // [{foo: "a"}, {foo: "b"}, {foo: "A"}, {foo: "c"}]
console.log(
dedupeBy(o => o.foo.toLowerCase()) (xs)); // [{foo: "a"}, {foo: "b"}, {foo: "c"}]
Mit diesen Kombinatoren sind wir äußerst flexibel im Umgang mit allen Arten von Deduplizierungsproblemen. Es ist nicht der schnellste Ansatz, sondern der aussagekräftigste und allgemeinste.
ich hatte ein etwas anderes Problem, wo ich Objekte mit doppelten ID-Eigenschaften aus einem Array entfernen musste. das hat funktioniert ..
let objArr = [ { id: '123' }, { id: '123' }, { id: '456' } ];
objArr = objArr.reduce( ( acc, cur ) => [
...acc.filter( ( obj ) => obj.id !== cur.id ), cur
], [] );
Ich habe eine Lösung, die es6-Methoden zum Reduzieren und Finden von Array-Hilfsmitteln zum Entfernen von Duplikaten verwendet.
let numbers = [2,2,3,3,5,6,6];
const removeDups = array => {
return array.reduce((acc, inc) => {
if(!acc.find( i => i === inc)) {
acc.Push(inc);
}
return acc;
},[]);
}
removeDups(numbers); /// [2,3,5,6]
Array.prototype.unique = function() {
var a = [],k = 0,e;
for(k=0;e=this[k];k++)
if(a.indexOf(e)==-1)
a.Push(e);
return a;
}
[1,2,3,4,33,23,2,3,22,1].unique(); // return [1,2,3,4,33,23,22]
Ich weiß, dass dies bereits zu Tode beantwortet wurde ... aber niemand hat die Javascript-Implementierung von linq ..__ erwähnt. Dann kann die .distinct()
-Methode verwendet werden - und macht den Code sehr einfach zu lesen.
var Linq = require('linq-es2015');
var distinctValues = Linq.asEnumerable(testValues)
.Select(x)
.distinct()
.toArray();
var testValues = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 1];
var distinctValues = Enumerable.asEnumerable(testValues)
.distinct()
.toArray();
console.log(distinctValues);
<script src="https://npmcdn.com/linq-es5/dist/linq.js"></script>
Erstellen eines Arrays aus eindeutigen Arrays mit Feld [2] als ID:
[ [ '497', 'Q0', 'WTX091-B06-138', '0', '1.000000000', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B09-92', '1', '0.866899288', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B09-92', '2', '0.846036819', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B09-57', '3', '0.835025326', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B43-79', '4', '0.765068215', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B43-56', '5', '0.764211464', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B44-448', '6', '0.761701704', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B44-12', '7', '0.761701704', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B49-128', '8', '0.747434800', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B18-17', '9', '0.746724770', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B19-374', '10', '0.733379549', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B19-344', '11', '0.731421782', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B09-92', '12', '0.726450470', 'GROUP001' ],
[ '497', 'Q0', 'WTX091-B19-174', '13', '0.712757036', 'GROUP001' ] ]
.filter((val1, idx1, arr) => !!~val1.indexOf(val1[2]) &&
!(arr.filter((val2, idx2) => !!~val2.indexOf(val1[2]) &&
idx2 < idx1).length));
Dieses ist nicht rein, es wird das Array modifizieren, aber dies ist das schnellste. Wenn deine schneller ist, dann schreibe bitte in die Kommentare;)
http://jsperf.com/unique-array-webdeb
Array.prototype.uniq = function(){
for(var i = 0, l = this.length; i < l; ++i){
var item = this[i];
var duplicateIdx = this.indexOf(item, i + 1);
while(duplicateIdx != -1) {
this.splice(duplicateIdx, 1);
duplicateIdx = this.indexOf(item, duplicateIdx);
l--;
}
}
return this;
}
[
"",2,4,"A","abc",
"",2,4,"A","abc",
"",2,4,"A","abc",
"",2,4,"A","abc",
"",2,4,"A","abc",
"",2,4,"A","abc",
"",2,4,"A","abc",
"",2,4,"A","abc"
].uniq() // ["",2,4,"A","abc"]
var numbers = [1,1,2,3,4,4];
function unique(dupArray) {
return dupArray.reduce(function (previous, num){
if (previous.find(function(item){
return item == num;
})) {
return previous;
} else {
previous.Push(num);
return previous;
}
}, [])
}
var check = unique(numbers);
console.log(check);
Noch eine andere Lösung für den Stapel.
Ich musste vor kurzem eine sortierte Liste eindeutig machen, und ich tat es mit einem Filter, der das vorherige Element in einem Objekt wie diesem verfolgt:
uniqueArray = sortedArray.filter(function(e) {
if(e==this.last)
return false;
this.last=e; return true;
},{last:null});
Mit Sets können Sie jetzt Duplikate entfernen und zurück in das Array konvertieren.
var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];
console.log([...new Set(names)])
Sie können Ramda.js verwenden, eine funktionale Javascript-Bibliothek, um dies zu tun:
var unique = R.uniq([1, 2, 1, 3, 1, 4])
console.log(unique)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
Dieses Skript modifiziert das Array und filtert doppelte Werte aus. Es funktioniert mit Zahlen und Strings.
https://jsfiddle.net/qsdL6y5j/1/
Array.prototype.getUnique = function () {
var unique = this.filter(function (elem, pos) {
return this.indexOf(elem) == pos;
}.bind(this));
this.length = 0;
this.splice(0, 0, unique);
}
var duplicates = [0, 0, 1, 1, 2, 3, 1, 1, 0, 4, 4];
duplicates.getUnique();
alert(duplicates);
Bei dieser Version können Sie stattdessen ein neues Array mit eindeutigem Wert zurückgeben, wobei das Original beibehalten wird (übergeben Sie einfach "true").
https://jsfiddle.net/dj7qxyL7/
Array.prototype.getUnique = function (createArray) {
createArray = createArray === true ? true : false;
var temp = JSON.stringify(this);
temp = JSON.parse(temp);
if (createArray) {
var unique = temp.filter(function (elem, pos) {
return temp.indexOf(elem) == pos;
}.bind(this));
return unique;
}
else {
var unique = this.filter(function (elem, pos) {
return this.indexOf(elem) == pos;
}.bind(this));
this.length = 0;
this.splice(0, 0, unique);
}
}
var duplicates = [0, 0, 1, 1, 2, 3, 1, 1, 0, 4, 4];
console.log('++++ ovveride')
duplicates.getUnique();
console.log(duplicates);
console.log('++++ new array')
var duplicates2 = [0, 0, 1, 1, 2, 3, 1, 1, 0, 4, 4];
var unique = duplicates2.getUnique(true);
console.log(unique);
console.log('++++ original')
console.log(duplicates2);
Browser support:
Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support (Yes) 1.5 (1.8) 9 (Yes) (Yes)
Die Version, die Selector akzeptiert, sollte ziemlich schnell und prägnant sein:
function unique(xs, f) {
var seen = {};
return xs.filter(function(x) {
var fx = (f && f(x)) || x;
return !seen[fx] && (seen[fx] = 1);
});
}
Dies ist eine ES6-Funktion, die Duplikate aus einem Array von Objekten entfernt und nach der angegebenen Objekteigenschaft filtert
function dedupe(arr = [], fnCheck = _ => _) {
const set = new Set();
let len = arr.length;
for (let i = 0; i < len; i++) {
const primitive = fnCheck(arr[i]);
if (set.has(primitive)) {
// duplicate, cut it
arr.splice(i, 1);
i--;
len--;
} else {
// new item, add it
set.add(primitive);
}
}
return arr;
}
const test = [
{video:{slug: "a"}},
{video:{slug: "a"}},
{video:{slug: "b"}},
{video:{slug: "c"}},
{video:{slug: "c"}}
]
console.log(dedupe(test, x => x.video.slug));
// [{video:{slug: "a"}}, {video:{slug: "b"}}, {video:{slug: "c"}}]
Wenn Sie eindeutige Werte sagen, bedeutet das für mich Werte, die nur einmal im Datensatz vorkommen.
Im Folgenden wird das Werte-Array gefiltert, wobei überprüft wird, ob der erste und der letzte Index eines bestimmten Werts gleich sind. Wenn der Index gleich ist, muss der Wert nur einmal vorkommen.
var values = [1, 2, 3, 4, 5, 2, 4, 6, 2, 1, 5];
var unique = values.filter(function(value) {
return values.indexOf(value) === values.lastIndexOf(value);
});
console.log(unique); // [3, 6]
Basierend auf Rückmeldungen, die ich falsch verstanden habe, folgt hier ein alternativer Ansatz, der eindeutige, nicht doppelte Werte aus dem Werte-Array liefert.
var values = [1, 2, 3, 4, 5, 2, 4, 6, 2, 1, 5];
var unique = values.reduce(function(unique, value) {
return unique.indexOf(value) === -1 ? unique.concat([value]) : unique;
}, []);
console.log(unique); // [1, 2, 3, 4, 5, 6]
Ähnlich der @ sergeyz-Lösung, jedoch kompakter durch Verwendung von Kurzformaten wie Pfeilfunktionen und array.includes
. Warnung: JSlint wird sich wegen der Verwendung des logischen oder und des Kommas beschweren. (obwohl immer noch perfekt gültiges Javascript)
my_array.reduce((a,k)=>(a.includes(k)||a.Push(k),a),[])
Viele Leute haben bereits erwähnt, dass sie ...
[...new Set(arr)];
Und das ist eine großartige Lösung, aber ich bevorzuge eine Lösung, die mit .filter
funktioniert. Meiner Meinung nach ist Filter ein natürlicherer Weg, um eindeutige Werte zu erhalten. Duplikate werden effektiv entfernt, und das Entfernen von Elementen aus einem Array ist genau das, wofür Filter gedacht sind. Sie können auch .map
, .reduce
und andere .filter
Anrufe verketten. Ich habe diese Lösung entwickelt ...
const unique = () => {
let cache;
return (elem, index, array) => {
if (!cache) cache = new Set(array);
return cache.delete(elem);
};
};
myArray.filter(unique());
Die Einschränkung ist, dass Sie eine Schließung benötigen, aber ich denke, dies ist ein angemessener Kompromiss. In Bezug auf die Leistung ist es performanter als die anderen Lösungen, die ich gesehen habe und die .filter
verwenden, aber schlechter als [...new Set(arr)]
.
Siehe auch mein Github-Paket youneek
Die obige Objektantwort scheint für mich in meinem Anwendungsfall mit Objekten nicht zu funktionieren.
Ich habe es wie folgt geändert:
var j = {};
this.forEach( function(v) {
var typ = typeof v;
var v = (typ === 'object') ? JSON.stringify(v) : v;
j[v + '::' + typ] = v;
});
return Object.keys(j).map(function(v){
if ( v.indexOf('::object') > -1 ) {
return JSON.parse(j[v]);
}
return j[v];
});
Dies scheint nun korrekt für Objekte, Arrays, Arrays mit gemischten Werten, Booleans usw. zu funktionieren.
Diese Lösung sollte sehr schnell sein und funktioniert in vielen Fällen.
Verwenden Sie die Funktion Object.keys
var indexArray = ["hi","welcome","welcome",1,-9];
var keyArray = {};
indexArray.forEach(function(item){ keyArray[item]=null; });
var uniqueArray = Object.keys(keyArray);
Manchmal muss ich eindeutige Vorkommen aus einer Reihe von Objekten abrufen. Lodash scheint ein netter Helfer zu sein, aber ich glaube nicht, dass das Filtern eines Arrays das Hinzufügen einer Abhängigkeit zu einem Projekt rechtfertigt.
Nehmen wir an, der Vergleich zweier Objekte ergibt sich aus dem Vergleich einer Eigenschaft, beispielsweise einer ID.
const a = [{id: 3}, {id: 4}, {id: 3}, {id: 5}, {id: 5}, {id: 5}];
Da wir alle Snippets mit einer Zeile lieben, können Sie dies folgendermaßen tun:
a.reduce((acc, curr) => acc.find(e => e.id === curr.id) ? acc : [...acc, curr], [])
Wenn Sie über ein Array von Objekten verfügen, und Sie eine uniqueBy
-Funktion wünschen, z. B. durch ein ID-Feld:
function uniqueBy(field, arr) {
return arr.reduce((acc, curr) => {
const exists = acc.find(v => v[field] === curr[field]);
return exists ? acc : acc.concat(curr);
}, [])
}
Ich habe ein einfaches Beispiel, in dem wir Objekte aus dem Array entfernen können, die eine wiederholte ID in Objekten haben.
let data = new Array({id: 1},{id: 2},{id: 3},{id: 1},{id: 3});
let unique = [];
let tempArr = [];
console.log('before', data);
data.forEach((value, index) => {
if (unique.indexOf(value.id) === -1) {
unique.Push(value.id);
} else {
tempArr.Push(index);
}
});
tempArr.reverse();
tempArr.forEach(ele => {
data.splice(ele, 1);
});
console.log(data);
Wenn die Reihenfolge nicht wichtig ist, können wir einen Hash erstellen und die Schlüssel für ein eindeutiges Array erhalten.
var ar = [1,3,4,5,5,6,5,6,2,1];
var uarEle = {};
links.forEach(function(a){ uarEle[a] = 1; });
var uar = keys(uarEle)
sie werden die einzigartigen Array-Elemente haben.
Noch eine Antwort, nur weil ich eine für meinen speziellen Anwendungsfall geschrieben habe. Ich habe das Array ohnehin sortiert, und da ich sortieren kann, kann ich das zum Deduplizieren verwenden.
Beachten Sie, dass meine Sortierung sich auf meine spezifischen Datentypen bezieht. Je nach Art der Elemente benötigen Sie möglicherweise eine andere Sortierung.
var sortAndDedup = function(array) {
array.sort(function(a,b){
if(isNaN(a) && isNaN(b)) { return a > b ? 1 : (a < b ? -1 : 0); }
if(isNaN(a)) { return 1; }
if(isNaN(b)) { return -1; }
return a-b;
});
var newArray = [];
var len = array.length;
for(var i=0; i<len; i++){
if(i === 0 || array[i] != array[i-1]){
newArray.Push(array[i]);
}
}
};
Verwenden Sie .toString () für Zeichenfolgen.
var givenvalues = [1,2,3,3,4,5,6];
var values = [];
for(var i=0; i<givenvalues.length; i++)
{
if(values.indexOf(givenvalues[i]) == -1)
{
values[values.length] = givenvalues[i];
}
}
Ich habe mir Joeytje50s Code über jsperf angesehen, der eine Reihe von Alternativen verglichen hat. Sein Code hatte viele kleinere Tippfehler, was sich auf die Leistung und die Richtigkeit auswirkte.
Noch wichtiger ist, dass er auf einem sehr kleinen Array testet. Ich habe ein Array mit 1000 ganzen Zahlen erstellt. Jede ganze Zahl war 100-mal eine zufällige ganze Zahl zwischen 0 und 1000. Dies ergibt im Durchschnitt etwa 1000/e = 368 Duplikate. Die Ergebnisse sind um jsperf .
Dies ist ein viel realistischeres Szenario, in dem Effizienz erforderlich sein könnte. Diese Änderungen haben dramatische Änderungen in den Behauptungen zur Folge (insbesondere der als am schnellsten angekündigte Code ist bei weitem nicht so schnell). Die offensichtlichen Gewinner sind dort, wo Hashtechniken eingesetzt werden, wobei der beste der beste ist
Array.prototype.getUnique3 = function(){
var u = Object.create(null), a = [];
for(var i = 0, l = this.length; i < l; ++i){
if(this[i] in u) continue;
a.Push(this[i]);
u[this[i]] = 1;
}
return a.length;
}
var a = [1,4,2,7,1,5,9,2,4,7,2]
var b = {}, c = {};
var len = a.length;
for(var i=0;i<len;i++){
a[i] in c ? delete b[a[i]] : b[a[i]] = true;
c[a[i]] = true;
}
// b contains all unique elements
Sie können die Hilfsfunktionen von Arrays "less" () und einige () verwenden, um Ihr Ergebnis zu erzielen. Überprüfen Sie mein Code-Snippet:
var arrayWithDuplicates = [0, 0, 1, 2, 3, 3, 4, 4, 'a', 'a', '', '', null, null];
var arrayWithUniqueValues = arrayWithDuplicates
.reduce((previous, item) => {
if(!previous.some(element => element === item)) {
previous.Push(item)
}
return previous;
}, []);
console.log('arrayWithUniqueValues', arrayWithUniqueValues)
Undefinierte Werte und Nullwerte werden herausgefiltert, da Sie sie meistens nicht benötigen.
const uniques = myArray.filter(e => e).filter((e, i, a) => a.indexOf(e) === i);
oder
const uniques = [...new Set(myArray.filter(e => e))];