J'ai une série de chiffres dont je dois m'assurer qu'ils sont uniques. J'ai trouvé l'extrait de code ci-dessous sur Internet et cela fonctionne très bien jusqu'à ce que la matrice contienne un zéro. J'ai trouvé cet autre script ici sur SO qui lui ressemble presque, mais il n'échoue pas.
Donc, dans le but de m'aider à apprendre, quelqu'un peut-il m'aider à déterminer où le script prototype se passe mal?
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;
}
Avec JavaScript 1.6/ECMAScript 5, vous pouvez utiliser la méthode native filter
d'un tableau de la manière suivante pour obtenir un tableau avec des valeurs uniques:
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']
La méthode native filter
parcourt le tableau et ne laisse que les entrées qui transmettent la fonction de rappel donnée onlyUnique
.
onlyUnique
vérifie si la valeur donnée est la première donnée. Si ce n'est pas le cas, il doit s'agir d'un duplicata et ne sera pas copié.
Cette solution fonctionne sans aucune bibliothèque supplémentaire comme jQuery ou prototype.js.
Cela fonctionne aussi pour les tableaux avec des types de valeurs mixtes.
Pour les anciens navigateurs (<ie9) qui ne prennent pas en charge les méthodes natives filter
et indexOf
, vous pouvez trouver des solutions dans la documentation MDN pour filter et indexOf .
Si vous souhaitez conserver la dernière occurrence d'une valeur, remplacez simplement indexOf
par lastIndexOf
.
Avec ES6, cela pourrait être réduit à ceci:
// 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']
Merci à Camilo Martin pour le conseil en commentaire.
ES6 a un objet natif Set
pour stocker des valeurs uniques. Pour obtenir un tableau avec des valeurs uniques, procédez comme suit:
var myArray = ['a', 1, 'a', 2, '1'];
let unique = [...new Set(myArray)];
// unique is ['a', 1, 2, '1']
Le constructeur de Set
prend un objet itérable, comme Array, et l'opérateur étendu ...
transforme l'ensemble en un tableau. Merci à Lukas Liese pour le commentaire en commentaire.
Réponse mise à jour pour ES6/ES2015: À l'aide de Set , la solution monoligne est la suivante:
var items = [4,5,4,6,3,4,5,2,23,1,4,4,4]
var uniqueItems = Array.from(new Set(items))
Qui retourne
[4, 5, 6, 3, 2, 23, 1]
Comme le suggère le_m , vous pouvez également le raccourcir avec l'opérateur spread , comme
var uniqueItems = [...new Set(items)]
Vous pouvez également utiliser nderscore.js .
console.log(_.uniq([1, 2, 1, 3, 1, 4]));
<script src="http://underscorejs.org/underscore-min.js"></script>
qui retournera:
[1, 2, 3, 4]
Je me rends compte que cette question a déjà plus de 30 réponses. Mais j'ai d'abord lu toutes les réponses existantes et fait mes propres recherches.
Je divise toutes les réponses en 4 solutions possibles:
[...new Set( [1, 1, 2] )];
{ }
pour éviter les doublons[ ]
filter + indexOf
Voici des exemples de codes trouvés dans les réponses:
[...new Set( [1, 1, 2] )];
function uniqueArray0(array) {
var result = Array.from(new Set(array));
return result
}
{ }
pour éviter les doublonsfunction 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;
}
Et je me demandais lequel est le plus rapide. J'ai créé exemple de feuille de calcul Google pour tester les fonctions. Remarque: ECMA 6 n’est pas disponible dans Google Sheets, je ne peux donc pas le tester.
Je m'attendais à ce que le code utilisant l'objet { }
l'emporte car il utilise le hachage. Je suis donc heureux que les tests aient montré les meilleurs résultats pour cet algorithme sous Chrome et IE. Merci à @rab pour le code .
J'ai depuis trouvé une méthode Nice qui utilise jQuery
arr = $.grep(arr, function(v, k){
return $.inArray(v ,arr) === k;
});
Remarque: Ce code a été extrait de Le poinçon de canard de Paul Irish - J'ai oublié de donner le crédit: P
La solution la plus courte avec ES6: [...new Set( [1, 1, 2] )];
Ou si vous souhaitez modifier le prototype Array (comme dans la question d'origine):
Array.prototype.getUnique = function() {
return [...new Set( [this] )];
};
EcmaScript 6 n'est pour le moment que partiellement implémenté dans les navigateurs modernes (août 2015), mais Babel est devenu très populaire pour transpiler ES6 (et même ES7) en ES5. De cette façon, vous pouvez écrire du code ES6 dès aujourd'hui!
Si vous vous demandez ce que signifie le ...
, il s'appelle l'opérateur spread . De MDN : «L'opérateur de diffusion permet de développer une expression à des endroits où plusieurs arguments (pour les appels de fonction) ou plusieurs éléments (pour les littéraux de tableau) sont attendus». Etant donné qu'un ensemble est un élément itératif (et ne peut avoir que des valeurs uniques), l'opérateur de diffusion le développera pour remplir le tableau.
Ressources pour apprendre ES6:
La solution la plus simple:
var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log([...new Set(arr)]);
Ou:
var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log(Array.from(new Set(arr)));
Le moyen le plus simple et le plus rapide (sous Chrome) consiste à:
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;
}
Parcourt simplement tous les éléments du tableau, vérifie si cet élément est déjà dans la liste et, dans le cas contraire, envoie au tableau renvoyé.
Selon jsPerf, cette fonction est la plus rapide de celles que je pourrais trouver nulle part - n'hésitez pas à ajouter la vôtre.
La version non prototype:
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;
}
Lorsque vous devez également trier le tableau, voici le plus rapide:
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;
}
ou non prototype:
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;
}
Ceci est également plus rapide que la méthode ci-dessus dans la plupart des navigateurs non chromés.
Beaucoup de réponses ici peuvent ne pas être utiles aux débutants. S'il est difficile de duper un tableau, vont-ils vraiment connaître la chaîne de prototypes, ou même jQuery?
Dans les navigateurs modernes, une solution simple et propre consiste à stocker les données dans un Set , conçu pour être une liste de valeurs uniques.
const cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
const uniqueCars = Array.from(new Set(cars));
Le Array.from
est utile pour convertir le set en tableau, afin que vous ayez facilement accès à toutes les superbes méthodes (fonctionnalités) des tableaux. Il y a aussi d'autres moyens de faire la même chose. Mais vous n’avez peut-être pas besoin de Array.from
du tout, car les sets offrent de nombreuses fonctionnalités utiles comme forEach .
Si vous devez prendre en charge l'ancien Internet Explorer et ne pouvez donc pas utiliser Set, une technique simple consiste à copier des éléments dans un nouveau tableau tout en vérifiant au préalable s'ils se trouvent déjà dans le nouveau tableau.
// 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);
}
});
Pour que cela soit immédiatement réutilisable, mettons-le dans une fonction.
function deduplicate(data) {
if (data.length > 0) {
var result = [];
data.forEach(function (elem) {
if (result.indexOf(elem) === -1) {
result.Push(elem);
}
});
return result;
}
}
Donc, pour éliminer les doublons, nous le ferions maintenant.
var uniqueCars = deduplicate(cars);
La partie deduplicate(cars)
devient la chose que nous avons nommée résultat lorsque la fonction est terminée.
Il suffit de lui donner le nom du tableau de votre choix.
["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;
}, []);
Ce prototype getUnique
n’est pas totalement correct, car si j’ai un tableau tel que: ["1",1,2,3,4,1,"foo"]
, il retournera ["1","2","3","4"]
et "1"
est une chaîne et 1
est un entier; ils sont différents.
Voici une solution correcte:
Array.prototype.unique = function(a){
return function(){ return this.filter(a) }
}(function(a,b,c){ return c.indexOf(a,b+1) < 0 });
en utilisant:
var foo;
foo = ["1",1,2,3,4,1,"foo"];
foo.unique();
Ce qui précède produira ["1",2,3,4,1,"foo"]
.
Nous pouvons le faire en utilisant les ensembles ES6:
var duplicatedArray = [1,2,3,4,5,1,1,1,2,3,4];
var uniqueArray = Array.from(new Set(duplicatedArray));
// Le résultat sera
uniqueArray = [1,2,3,4,5];
Sans étendre Array.prototype (c'est une mauvaise pratique) ni utiliser jquery/underscore, vous pouvez simplement filter
le tableau.
En gardant la dernière occurrence:
function arrayLastUnique(array) {
return array.filter(function (a, b, c) {
// keeps last occurrence
return c.indexOf(a, b + 1) < 0;
});
},
ou première occurrence:
function arrayFirstUnique(array) {
return array.filter(function (a, b, c) {
// keeps first occurrence
return c.indexOf(a) === b;
});
},
Eh bien, il s’agit uniquement de javascript ECMAScript 5+, ce qui signifie uniquement IE9 +, mais c’est bien pour un développement en HTML/JS natif (App Windows Store, Firefox OS, Sencha, Phonegap, Titanium, ...).
En effet, 0
est une valeur de fausseté en JavaScript.
this[i]
sera faux si la valeur du tableau est 0 ou toute autre valeur de faux.
Si vous utilisez le framework Prototype, il n'est pas nécessaire de faire des boucles "pour", vous pouvez utiliser http://www.prototypejs.org/api/array/uniq comme ceci:
var a = Array.uniq();
Ce qui produira un tableau dupliqué sans doublons. Je suis tombé sur votre question à la recherche d'une méthode pour compter les enregistrements de tableaux distincts afin qu'après
uniq ()
J'ai utilisé
taille()
et il y avait mon résultat simple. p.s. Désolé si j'ai mal tapé quelque chose
edit: si vous voulez échapper à des enregistrements non définis, vous voudrez peut-être ajouter
compact()
avant, comme ceci:
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
}
étrange cela n’a pas été suggéré auparavant .. pour supprimer les doublons par clé d’objet (id
ci-dessous) dans un tableau, vous pouvez faire quelque chose comme ceci:
const uniqArray = array.filter((obj, idx, arr) => (
arr.findIndex((o) => o.id === obj.id) === idx
))
Je ne suis pas sûr de savoir pourquoi Gabriel Silveira a écrit la fonction de cette façon, mais une forme plus simple qui fonctionne aussi bien pour moi et sans la minification est:
Array.prototype.unique = function() {
return this.filter(function(value, index, array) {
return array.indexOf(value, index + 1) < 0;
});
};
ou en CoffeeScript:
Array.prototype.unique = ->
this.filter( (value, index, array) ->
array.indexOf(value, index + 1) < 0
)
Recherche de valeurs de tableau uniques dans une méthode simple
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]
De Shamasis Bhattacharya blog de ((O (2n) complexité temporelle):
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;
};
Du blog de Paul Irish : amélioration de 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]
Pour résoudre le problème dans l'autre sens, il peut être utile de ne pas dupliquer le contenu de votre tableau, comme le ferait l'objet Set , mais il n'est pas encore disponible dans tous les navigateurs. Il économise de la mémoire et est plus efficace si vous devez consulter son contenu plusieurs fois.
Array.prototype.add = function (elem) {
if (this.indexOf(elem) == -1) {
this.Push(elem);
}
}
Échantillon:
set = [];
[1,3,4,1,2,1,3,3,4,1].forEach(function(x) { set.add(x); });
Vous donne set = [1,3,4,2]
a.filter(( t={}, e=>!(t[e]=e in t) ))
O(n)performance ; nous supposons que votre tableau est en a
. Explication ici (+ Jeppe amélioration)
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) );
J'ai trouvé que la sérialisation leur clé de hachage m'a aidé à obtenir ce travail pour les objets.
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;
}
Si quelqu'un utilise knockoutjs
ko.utils.arrayGetDistinctValues()
BTW a regardé tous les utilitaires ko.utils.array*
.
Si vous êtes d'accord avec des dépendances supplémentaires ou si vous avez déjà l'une des bibliothèques dans votre base de code, vous pouvez supprimer les doublons d'un tableau à l'aide de LoDash (ou Underscore).
Utilisation
Si vous ne l'avez pas déjà dans votre base de code, installez-le en utilisant npm:
npm install lodash
Puis utilisez-le comme suit:
import _ from 'lodash';
let idArray = _.uniq ([
1,
2,
3,
3,
3
]);
console.dir(idArray);
En dehors:
[ 1, 2, 3 ]
Vous pouvez également utiliser sugar.js:
[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);
Regarde ça. Jquery fournit la méthode uniq suivante: 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
});
En utilisant des clés d’objet pour créer un tableau unique, j’ai essayé de suivre
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]);
Ce qui retourne ["1", 1, 2, 3, 4, "foo", false, null]
Je pense que c'est le moyen le plus simple d'obtenir un élément unique d'un tableau.
var arr = [1,2,4,1,4];
arr = Array.from(new Set(arr))
console.log(arr)
Si vous avez la puissante méthode reduction disponible ( ≥ 5.1 ), vous pouvez essayer quelque chose comme ceci:
Array.prototype.uniq = function() {
return this.reduce(function(sofar, cur) {
return sofar.indexOf(cur) < 0 ? sofar.concat([cur]) : sofar;
}, []);
};
Ce n’est pas l’implémentation la plus efficace (en raison de la vérification indexOf
qui, dans le pire des cas, peut parcourir toute la liste). Si l'efficacité est importante, vous pouvez conserver "l'historique" des occurrences dans une structure à accès aléatoire (par exemple, {}
) et les saisir à la place. C’est essentiellement ce que la réponse la plus votée fait, alors jetez-y un exemple.
[...new Set(duplicates)]
C’est le plus simple et référencé depuis MDN Web Docs.
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]
Cela fonctionnera.
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;
}
Faites-le avec lodash et la fonction identity lambda, définissez-la simplement avant d'utiliser votre objet
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'])
et aura:
[{a:1,b:2},{a:1,b:3}]
[1,2,3,'a','x']
(c'est le moyen le plus simple)
En vous appuyant sur d’autres réponses, voici une autre variante qui utilise un indicateur facultatif pour choisir une stratégie (conserver la première occurrence ou conserver la dernière):
Sans extension 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]
Extension 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]
Vous pouvez également utiliser jQuery
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]
A l'origine répondu à: fonction jQuery pour obtenir tous les éléments uniques d'un tableau?
La déduplication nécessite généralement un opérateur d'égalité pour le type donné. Cependant, l'utilisation d'une fonction eq
nous empêche d'utiliser un Set
pour déterminer les doublons de manière efficace, car Set
retombe à ===
. Comme vous le savez sûrement, ===
ne fonctionne pas pour les types de référence. Donc, nous sommes gentils si coincés, non?
La solution consiste simplement à utiliser une fonction de transformation qui nous permet de transformer un type (de référence) en quelque chose que nous pouvons réellement rechercher à l'aide de Set
. Nous pourrions utiliser une fonction de hachage, par exemple, ou JSON.stringify
la structure de données, si elle ne contient aucune fonction.
Souvent, nous n'avons besoin que d'accéder à une propriété, que nous pouvons ensuite comparer à la place de la référence de Object
.
Voici deux combinateurs qui répondent à ces exigences:
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"}]
Avec ces combinateurs, nous sommes extrêmement flexibles dans le traitement de toutes sortes de problèmes de déduplication. Ce n'est pas l'approche du jeûne, mais l'approche la plus expressive et la plus générique.
j'ai eu un problème légèrement différent où j'avais besoin de supprimer des objets avec les propriétés en double id d'un tableau. cela a fonctionné ..
let objArr = [ { id: '123' }, { id: '123' }, { id: '456' } ];
objArr = objArr.reduce( ( acc, cur ) => [
...acc.filter( ( obj ) => obj.id !== cur.id ), cur
], [] );
J'ai une solution qui utilise es6 réduire et trouver des méthodes d'assistance de tableau pour supprimer les doublons.
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]
Je sais que la réponse à cette question est déjà mortelle ... mais .... personne n'a mentionné l'implémentation javascript de linq . Ensuite, la méthode .distinct()
peut être utilisée - et cela rend le code super facile à lire.
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>
Créer un tableau de tableaux uniques, en utilisant le champ [2] comme identifiant:
[ [ '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));
Celui-ci n'est pas pur, il modifiera le tableau, mais c'est le plus rapide. Si le vôtre est plus rapide, alors s'il vous plaît écrivez dans les commentaires;)
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);
Encore une autre solution pour la pile.
J'ai récemment eu besoin de rendre une liste triée unique et je l'ai fait en utilisant un filtre qui garde la trace de l'élément précédent dans un objet tel que
uniqueArray = sortedArray.filter(function(e) {
if(e==this.last)
return false;
this.last=e; return true;
},{last:null});
Maintenant, en utilisant des ensembles, vous pouvez supprimer les doublons et les reconvertir dans le tableau.
var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];
console.log([...new Set(names)])
Vous pouvez utiliser Ramda.js , une bibliothèque javascript fonctionnelle pour faire ceci:
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>
Ce script modifie le tableau en filtrant les valeurs dupliquées. Cela fonctionne avec des nombres et des chaînes.
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);
Cette version vous permet plutôt de renvoyer un nouveau tableau avec une valeur unique en conservant l’original (il suffit de transmettre 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)
La version qui accepte le sélecteur, devrait être assez rapide et concise:
function unique(xs, f) {
var seen = {};
return xs.filter(function(x) {
var fx = (f && f(x)) || x;
return !seen[fx] && (seen[fx] = 1);
});
}
Il s'agit d'une fonction ES6 qui supprime les doublons d'un tableau d'objets, en filtrant par la propriété d'objet spécifiée
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"}}]
Pour moi, lorsque vous parlez de valeurs uniques, cela signifie pour moi des valeurs qui apparaissent une et une seule fois dans le jeu de données.
Ce qui suit filtre le tableau de valeurs, en vérifiant que le premier et le dernier index d’une valeur donnée sont égaux. Si l'index est égal, cela signifie que la valeur ne doit apparaître qu'une seule fois.
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]
Sur la base des commentaires selon lesquels j'ai mal compris la question, voici une approche alternative qui renverra des valeurs uniques non dupliquées à partir du tableau de valeurs.
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]
Semblable à la solution @sergeyz, mais plus compact en utilisant davantage de formats abrégés tels que les fonctions de flèche et array.includes
. Attention: JSlint va se plaindre à cause de l’utilisation du ou logique et de la virgule. (javascript parfaitement valide cependant)
my_array.reduce((a,k)=>(a.includes(k)||a.Push(k),a),[])
Beaucoup de gens ont déjà mentionné l'utilisation de ...
[...new Set(arr)];
Et ceci est une excellente solution, mais ma préférence est une solution qui fonctionne avec .filter
. À mon avis, le filtre est un moyen plus naturel d’obtenir des valeurs uniques. Vous supprimez efficacement les doublons, et supprimer les éléments d'un tableau correspond exactement au filtre. Il vous permet également d’enchaîner .map
, .reduce
et d’autres appels .filter
. J'ai conçu cette solution ...
const unique = () => {
let cache;
return (elem, index, array) => {
if (!cache) cache = new Set(array);
return cache.delete(elem);
};
};
myArray.filter(unique());
La mise en garde est que vous avez besoin d'une fermeture, mais je pense que c'est un bon compromis. En termes de performances, elle est plus performante que les autres solutions que j'ai déjà publiées et qui utilise .filter
, mais moins performante que [...new Set(arr)]
.
Voir aussi mon paquet github youneek
La réponse à l'objet ci-dessus ne semble pas fonctionner pour moi dans mon cas d'utilisation d'Object.
Je l'ai modifié comme suit:
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];
});
Cela semble maintenant fonctionner correctement pour les objets, les tableaux, les tableaux avec des valeurs mélangées, les booléens, etc.
Cette solution devrait être très rapide et fonctionnera dans de nombreux cas.
Utiliser la fonction Object.keys
var indexArray = ["hi","welcome","welcome",1,-9];
var keyArray = {};
indexArray.forEach(function(item){ keyArray[item]=null; });
var uniqueArray = Object.keys(keyArray);
Si vous avez un tableau d'objets et que vous voulez une fonction uniqueBy
, disons, par un champ id:
function uniqueBy(field, arr) {
return arr.reduce((acc, curr) => {
const exists = acc.find(v => v[field] === curr[field]);
return exists ? acc : acc.concat(curr);
}, [])
}
J'ai un exemple simple où nous pouvons supprimer des objets d'un tableau ayant un identifiant répété dans des objets,
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);
Si l'ordre n'est pas important, nous pouvons créer un hachage et obtenir les clés pour créer un tableau unique.
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)
uar aura les éléments uniques du tableau.
Encore une autre réponse, juste parce que j’en ai écrit une pour mon cas d’utilisation spécifique. De toute façon, j’ai été en train de trier le tableau, et si je trie, je peux l’utiliser pour dédupliquer.
Notez que ma sorte traite de mes types de données spécifiques, vous aurez peut-être besoin d'une sorte différente en fonction du type d'éléments que vous avez.
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]);
}
}
};
Utilisez .toString () pour les chaînes.
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];
}
}
J'ai regardé le code de Joeytje50 sur jsperf qui a comparé un certain nombre d'alternatives. Son code comportait de nombreuses fautes de frappe mineures, ce qui faisait une différence dans les performances et l'exactitude.
Plus important encore, il teste sur un très petit tableau. J'ai fait un tableau avec 1000 entiers. Chaque nombre entier était 100 fois un nombre entier aléatoire compris entre 0 et 1 000. Cela donne environ 1000/e = 368 doublons en moyenne. Les résultats sont à jsperf .
Il s’agit d’un scénario beaucoup plus réaliste où l’efficacité pourrait être nécessaire. Ces changements apportent des changements dramatiques dans les revendications (spécifiquement, le code présenté comme le plus rapide est loin d'être rapide). Les gagnants évidents sont ceux qui utilisent les techniques de hachage, le meilleur étant
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
Vous pouvez utiliser les fonctions d’aide des tableaux, reduction () et certaines () pour obtenir votre résultat. Vérifiez mon extrait de code:
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)
Pour filtrer les valeurs indéfinies et nulles car vous n'en avez généralement pas besoin.
const uniques = myArray.filter(e => e).filter((e, i, a) => a.indexOf(e) === i);
ou
const uniques = [...new Set(myArray.filter(e => e))];