web-dev-qa-db-fra.com

Comment obtenir des valeurs uniques dans un tableau

Comment puis-je obtenir une liste de valeurs uniques dans un tableau? Dois-je toujours utiliser un deuxième tableau ou existe-t-il quelque chose de similaire au hashmap de Java en JavaScript?

Je vais utiliser JavaScript et jQuery only. Aucune bibliothèque supplémentaire ne peut être utilisée.

123
Astronaut

Puisque j'en ai parlé dans les commentaires de la réponse de @ Rocket, je pourrais aussi bien donner un exemple qui n'utilise aucune bibliothèque. Cela nécessite deux nouvelles fonctions prototypes, contains et unique

Array.prototype.contains = function(v) {
    for(var i = 0; i < this.length; i++) {
        if(this[i] === v) return true;
    }
    return false;
};

Array.prototype.unique = function() {
    var arr = [];
    for(var i = 0; i < this.length; i++) {
        if(!arr.includes(this[i])) {
            arr.Push(this[i]);
        }
    }
    return arr; 
}

Vous pouvez alors faire:

var duplicates = [1,3,4,2,1,2,3,8];
var uniques = duplicates.unique(); // result = [1,3,4,2,8]

Pour plus de fiabilité, vous pouvez remplacer contains par indexOf du MDN et vérifier si chaque élément indexOf est égal à -1: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf

102
jackwanders

Ou pour ceux qui recherchent un one-liner (simple et fonctionnel), compatible avec les navigateurs actuels:

var a = ["1", "1", "2", "3", "3", "1"];
var unique = a.filter(function(item, i, ar){ return ar.indexOf(item) === i; });

Mise à jour 18-04-17

Il semble que "Array.prototype.includes" bénéficie désormais d'un support étendu dans les dernières versions des principaux navigateurs ( compatibilité ).

Mise à jour du 29/07/2015:

Il est prévu que les navigateurs prennent en charge une méthode standardisée 'Array.prototype.includes' qui, bien que ne répondant pas directement à cette question; est souvent liée. 

Usage:

["1", "1", "2", "3", "3", "1"].includes("2");     // true

Pollyfill ( support du navigateur , source de mozilla ):

// https://tc39.github.io/ecma262/#sec-array.prototype.includes
if (!Array.prototype.includes) {
  Object.defineProperty(Array.prototype, 'includes', {
    value: function(searchElement, fromIndex) {

      // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If len is 0, return false.
      if (len === 0) {
        return false;
      }

      // 4. Let n be ? ToInteger(fromIndex).
      //    (If fromIndex is undefined, this step produces the value 0.)
      var n = fromIndex | 0;

      // 5. If n ≥ 0, then
      //  a. Let k be n.
      // 6. Else n < 0,
      //  a. Let k be len + n.
      //  b. If k < 0, let k be 0.
      var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

      // 7. Repeat, while k < len
      while (k < len) {
        // a. Let elementK be the result of ? Get(O, ! ToString(k)).
        // b. If SameValueZero(searchElement, elementK) is true, return true.
        // c. Increase k by 1.
        // NOTE: === provides the correct "SameValueZero" comparison needed here.
        if (o[k] === searchElement) {
          return true;
        }
        k++;
      }

      // 8. Return false
      return false;
    }
  });
}
162
Josh Mc

Voici une solution beaucoup plus propre pour ES6 que je ne vois pas incluse ici. Il utilise les opérateurs Set et spread : ...

var a = [1, 1, 2];

[... new Set(a)]

Ce qui retourne [1, 2]

68
Charles Clayton

Si vous voulez laisser le tableau d'origine intact, 

vous avez besoin d'un second tableau pour contenir les éléments uniqe du premier

La plupart des navigateurs ont Array.prototype.filter:

var unique= array1.filter(function(itm, i){
    return array1.indexOf(itm)== i; 
    // returns true for only the first instance of itm
});


//if you need a 'shim':
Array.prototype.filter= Array.prototype.filter || function(fun, scope){
    var T= this, A= [], i= 0, itm, L= T.length;
    if(typeof fun== 'function'){
        while(i<L){
            if(i in T){
                itm= T[i];
                if(fun.call(scope, itm, i, T)) A[A.length]= itm;
            }
            ++i;
        }
    }
    return A;
}
 Array.prototype.indexOf= Array.prototype.indexOf || function(what, i){
        if(!i || typeof i!= 'number') i= 0;
        var L= this.length;
        while(i<L){
            if(this[i]=== what) return i;
            ++i;
        }
        return -1;
    }
15
kennebec

De nos jours, vous pouvez utiliser le type de données Set d'ES6 pour convertir votre tableau en un ensemble unique. Ensuite, si vous devez utiliser des méthodes de tableau, vous pouvez le reconvertir en tableau:

var arr = ["a", "a", "b"];
var uniqueSet = new Set(arr); // {"a", "b"}
var uniqueArr = Array.from(uniqueSet); // ["a", "b"]
//Then continue to use array methods:
uniqueArr.join(", "); // "a, b"
12
Fawntasia

Maintenant, dans ES6, nous pouvons utiliser la nouvelle fonction ES6

var items = [1,1,1,1,3,4,5,2,23,1,4,4,4,2,2,2]
var uniqueItems = Array.from(new Set(items))

Il retournera le résultat unique.

[1, 3, 4, 5, 2, 23]
12
Rohit.007

En utilisant EcmaScript 2016, vous pouvez simplement le faire comme ceci.

 var arr = ["a", "a", "b"];
 var uniqueArray = Array.from(new Set(arr)); // Unique Array ['a', 'b'];

Les ensembles sont toujours uniques et, à l’aide de Array.from(), vous pouvez convertir un ensemble en tableau. Pour référence, regardez les documentations.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fromhttps://developer.mozilla.org/en-US/ docs/Web/JavaScript/Référence/Global_Objects/Set

11
Adeel Imran

Solution courte et douce utilisant un second tableau;

var axes2=[1,4,5,2,3,1,2,3,4,5,1,3,4];

    var distinct_axes2=[];

    for(var i=0;i<axes2.length;i++)
        {
        var str=axes2[i];
        if(distinct_axes2.indexOf(str)==-1)
            {
            distinct_axes2.Push(str);
            }
        }
    console.log("distinct_axes2 : "+distinct_axes2); // distinct_axes2 : 1,4,5,2,3
7
Pradip Shenolkar

En utilisant jQuery, voici une fonction unique de Array que j'ai créée:

Array.prototype.unique = function () {
    var arr = this;
    return $.grep(arr, function (v, i) {
        return $.inArray(v, arr) === i;
    });
}

console.log([1,2,3,1,2,3].unique()); // [1,2,3]
6
Rocket Hazmat

Pas natif en Javascript, mais beaucoup de bibliothèques ont cette méthode.

_.uniq(array) ( link ) de Underscore.js fonctionne assez bien ( source ).

5
Calvin

Vous avez seulement besoin de Vanilla JS pour trouver des pièces uniques avec Array.some et Array.reduce. Avec la syntaxe ES2015, ce n'est que 62 caractères. 

a.reduce((c, v) => b.some(w => w === v) ? c : c.concat(v)), b)

Array.some et Array.reduce sont pris en charge par IE9 + et d'autres navigateurs. Il suffit de changer les fonctions de flèche épaisse pour que les fonctions habituelles soient prises en charge dans les navigateurs qui ne prennent pas en charge la syntaxe ES2015.

var a = [1,2,3];
var b = [4,5,6];
// .reduce can return a subset or superset
var uniques = a.reduce(function(c, v){
    // .some stops on the first time the function returns true                
    return (b.some(function(w){ return w === v; }) ?  
      // if there's a match, return the array "c"
      c :     
      // if there's no match, then add to the end and return the entire array                                        
      c.concat(v)}),                                  
  // the second param in .reduce is the starting variable. This is will be "c" the first time it runs.
  b);                                                 

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/somehttps://developer.mozilla.org/fr docs/Web/JavaScript/Référence/Global_Objects/Array/Réduire

4
puppybits

La majorité des solutions ci-dessus ont une complexité de temps d'exécution élevée. 

Voici la solution qui utilise reduce et peut effectuer le travail en O(n) heure.  

Array.prototype.unique = Array.prototype.unique || function() {
        var arr = [];
	this.reduce(function (hash, num) {
		if(typeof hash[num] === 'undefined') {
			hash[num] = 1; 
			arr.Push(num);
		}
		return hash;
	}, {});
	return arr;
}
    
var myArr = [3,1,2,3,3,3];
console.log(myArr.unique()); //[3,1,2];

Remarque:

Cette solution ne dépend pas de réduire. L'idée est de créer une carte d'objets et d'insérer des objets uniques dans le tableau.

3
Rahul Arora

Rapide, compact, pas de boucles imbriquées, fonctionne avec n'importe quel objet, pas seulement des chaînes et des nombres, prend un prédicat et seulement 5 lignes de code !!

function findUnique(arr, predicate) {
  var found = {};
  arr.forEach(d => {
    found[predicate(d)] = d;
  });
  return Object.keys(found).map(key => found[key]); 
}

Exemple: Pour trouver des articles uniques par type:

var things = [
  { name: 'charm', type: 'quark'},
  { name: 'strange', type: 'quark'},
  { name: 'proton', type: 'boson'},
];

var result = findUnique(things, d => d.type);
//  [
//    { name: 'charm', type: 'quark'},
//    { name: 'proton', type: 'boson'}
//  ] 

Si vous voulez qu'il trouve le premier élément unique au lieu du dernier, ajoutez un enregistrement found.hasOwnPropery ().

2
user1618323

Vous pouvez entrer un tableau avec des doublons et la méthode ci-dessous renverra un tableau avec des éléments uniques.

function getUniqueArray(array){
    var uniqueArray = [];
    uniqueArray[0] = array[0];
    for(var i = 0; i < array.length; i++){
        var isExist = false;
        for(var j = 0; j < uniqueArray.length; j++){
            if(array[i] == uniqueArray[j]){
                isExist = true;
                break;
            }
            else{
                isExist = false;
            }
        }
        if(isExist == false){
            uniqueArray[uniqueArray.length] = array[i];
        }
    }
    return uniqueArray;
}
1
honey

vous pouvez utiliser,

let arr1 = [1,2,1,3];
let arr2 = [2,3,4,5,1,2,3];

let arr3 = [...new Set([...arr1,...arr2])];

il vous donnera des éléments uniques,

**> mais il y a un piège,

pour ce "1" et 1 et sont des éléments diff, **

la deuxième option consiste à utiliser la méthode de filtrage sur le tableau.

1
niranjan harpale

J'ai essayé ce problème en pur JS . J'ai suivi les étapes suivantes 1. Trier le tableau donné, 2. parcourir le tableau trié, 3. Vérifier les valeurs précédentes et suivantes avec la valeur actuelle

// JS
var inpArr = [1, 5, 5, 4, 3, 3, 2, 2, 2,2, 100, 100, -1];

//sort the given array
inpArr.sort(function(a, b){
    return a-b;
});

var finalArr = [];
//loop through the inpArr
for(var i=0; i<inpArr.length; i++){
    //check previous and next value 
  if(inpArr[i-1]!=inpArr[i] && inpArr[i] != inpArr[i+1]){
        finalArr.Push(inpArr[i]);
  }
}
console.log(finalArr);

Démo

0
Sanketh Nayak

Une autre pensée de cette question. Voici ce que j'ai fait pour y parvenir avec moins de code.

var distinctMap = {};
var testArray = ['John', 'John', 'Jason', 'Jason'];
for (var i = 0; i < testArray.length; i++) {
  var value = testArray[i];
  distinctMap[value] = '';
};
var unique_values = Object.keys(distinctMap);
0
Xing-Wei Lin
Array.prototype.unique = function () {
    var dictionary = {};
    var uniqueValues = [];
    for (var i = 0; i < this.length; i++) {
        if (dictionary[this[i]] == undefined){
            dictionary[this[i]] = i;
            uniqueValues.Push(this[i]);
        }
    }
    return uniqueValues; 
}
0
Hexer338

Le seul problème avec les solutions apportées jusqu’à présent est l’efficacité. Si cela vous préoccupe (et vous devriez probablement le faire), vous devez éviter les boucles imbriquées: pour * pour, filter * indexOf, grep * inArray, ils effectuent tous une itération du tableau plusieurs fois. Vous pouvez implémenter une boucle unique avec des solutions telles que this ou this

0
Jesús Carrera
function findUnique(arr) {
    var result = [];
    arr.forEach(function (d) {
        if (result.indexOf(d) === -1)
            result.Push(d);
    });
    return result;
}

var unique = findUnique([1, 2, 3, 1, 2, 1, 4]); // [1,2,3,4]
0
user1739150

Si vous n'avez pas à vous soucier des anciens navigateurs, c'est exactement ce pour quoi les ensembles sont conçus.

L'objet Set vous permet de stocker des valeurs uniques de tout type, que ce soit valeurs primitives ou références d'objet.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

const set1 = new Set([1, 2, 3, 4, 5, 1]);
// returns Set(5) {1, 2, 3, 4, 5}
0
Paul Cooper

Sachant que indexOf renverra la première occurrence d'un élément, vous pouvez faire quelque chose comme ceci:

Array.prototype.unique = function(){
        var self = this;
        return this.filter(function(elem, index){
            return self.indexOf(elem) === index;
        })
    }
0
nikksan

Façon ES6:

const uniq = (arr) => (arr.filter((item, index, arry) => (arry.indexOf(item) === index)));
0
Ashwin Aggarwal
function findUniques(arr){
  let uniques = []
  arr.forEach(n => {
    if(!uniques.includes(n)){
      uniques.Push(n)
    }       
  })
  return uniques
}

let arr = ["3", "3", "4", "4", "4", "5", "7", "9", "b", "d", "e", "f", "h", "q", "r", "t", "t"]

findUniques(arr)
// ["3", "4", "5", "7", "9", "b", "d", "e", "f", "h", "q", "r", "t"]
0
smithWEBtek