Comment obtenir des valeurs distinctes d'un tableau d'objets en JavaScript?

386

En supposant que j'ai les éléments suivants:

var array = 
    [
        {"name":"Joe", "age":17}, 
        {"name":"Bob", "age":17}, 
        {"name":"Carl", "age": 35}
    ]

Quelle est la meilleure façon d'obtenir un tableau de tous les âges distincts, de sorte que j'obtienne un tableau de résultats de:

[17, 35]

Existe-t-il un moyen de structurer alternativement les données ou une meilleure méthode de telle sorte que je n'aurais pas à parcourir chaque tableau en vérifiant la valeur de "age" et en vérifiant par rapport à un autre tableau son existence, et en l'ajoutant sinon?

S'il y avait un moyen, je pourrais simplement retirer les âges distincts sans répéter ...

La manière actuellement inefficace que je voudrais améliorer ... Si cela signifie qu'au lieu de "tableau" étant un tableau d'objets, mais une "carte" d'objets avec une clé unique (c'est-à-dire "1,2,3") qui serait d'accord aussi. Je cherche juste le moyen le plus efficace en termes de performances.

Voici comment je le fais actuellement, mais pour moi, l'itération semble juste minable pour l'efficacité même si cela fonctionne ...

var distinct = []
for (var i = 0; i < array.length; i++)
   if (array[i].age not in distinct)
      distinct.push(array[i].age)
Rolando
la source
34
l'itération n'est pas "minable pour l'efficacité" et vous ne pouvez rien faire pour chaque élément "sans itérer". vous pouvez utiliser diverses méthodes fonctionnelles, mais en fin de compte, quelque chose à un certain niveau doit itérer sur les éléments.
Evoli
// 100% de code en cours d'exécution const listOfTags = [{id: 1, libellé: "Bonjour", couleur: "rouge", tri: 0}, {id: 2, libellé: "Monde", couleur: "vert", tri : 1}, {id: 3, libellé: "Bonjour", couleur: "bleu", tri: 4}, {id: 4, libellé: "Sunshine", couleur: "jaune", tri: 5}, {id : 5, étiquette: "Bonjour", couleur: "rouge", tri: 6}], touches = ['étiquette', 'couleur'], filtré = listOfTags.filter ((s => o => (k => ! s.has (k) && s.add (k)) (keys.map (k => o [k]). join ('|'))) (nouvel ensemble)); console.log (filtré);
Sandeep Mishra
1
la prime est excellente, mais la question avec les données et la réponse fournies est déjà répondue ici: stackoverflow.com/questions/53542882/… . quel est le but de la prime? dois-je répondre à ce problème particulier avec deux ou plusieurs clés?
Nina Scholz
Setobjet et maps sont inutiles. Ce travail ne prend qu'une .reduce()étape simple .
Redu

Réponses:

128

Si c'était PHP, je construirais un tableau avec les clés et le prendrais array_keysà la fin, mais JS n'a pas un tel luxe. Essayez plutôt ceci:

var flags = [], output = [], l = array.length, i;
for( i=0; i<l; i++) {
    if( flags[array[i].age]) continue;
    flags[array[i].age] = true;
    output.push(array[i].age);
}
Niet l'Absolu Noir
la source
15
Non, car array_uniquecomparerait l'ensemble de l'article, pas seulement l'âge comme demandé ici.
Niet the Dark Absol
6
Je pense que flags = {}c'est mieux queflags = []
zhuguowei
3
@zhuguowei peut-être, bien qu'il n'y ait rien de vraiment mal avec les tableaux clairsemés - et j'ai également supposé qu'il ages'agit d'un nombre relativement petit (<120 sûrement)
Niet the Dark Absol
comment pourrions-nous également imprimer le nombre total de personnes du même âge?
user1788736
609

Si vous utilisez ES6 / ES2015 ou une version ultérieure, vous pouvez le faire de cette façon:

const unique = [...new Set(array.map(item => item.age))];

Voici un exemple sur la façon de procéder.

Vlad Bezden
la source
11
Je reçois une erreur:TypeError: (intermediate value).slice is not a function
AngJobs sur Github
7
@Thomas ... signifie opérateur de spread. Dans ce cas, cela signifie créer un nouvel ensemble et le diffuser dans une liste. Vous pouvez trouver plus d'informations à ce sujet ici: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Vlad Bezden
10
pour la dactylographie, vous devez utiliser un nouvel ensemble enveloppé dans Array.from () ... je fournirai cette réponse ci-dessous. @AngJobs
Christian Matthew
4
est-il possible de trouver des objets uniques en fonction de plusieurs clés dans l'objet?
Jefree Sujit
14
Cette solution a été donnée presque mot pour mot quelques mois plus tôt par @Russell Vea. Avez-vous vérifié les réponses existantes? Mais là encore, 266+ votes montrent que personne d'autre n'a vérifié non plus.
Dan Dascalescu
166

en utilisant ES6

let array = [
  { "name": "Joe", "age": 17 },
  { "name": "Bob", "age": 17 },
  { "name": "Carl", "age": 35 }
];
array.map(item => item.age)
  .filter((value, index, self) => self.indexOf(value) === index)

> [17, 35]
Ivan Nosov
la source
2
Si je veux obtenir la valeur avec son index, alors comment puis-je obtenir Exemple: je veux obtenir {"nom": "Bob", "âge": "17"}, {"nom": "Bob", "âge ":" 17 "}
Abdullah Al Mamun
10
C'est pourquoi vous devez continuer à faire défiler
Alejandro Bastidas
5
@AbdullahAlMamun vous pouvez utiliser la carte dans .filter au lieu d'appeler .map d'abord, comme ceci:array.filter((value, index, self) => self.map(x => x.age).indexOf(value.age) == index)
Leo
1
ps: .map à l'intérieur de .filter peut être lent, donc soyez prudent avec les grands tableaux
Leo
2
@IvanNosov votre extrait est très bon, bien que plusieurs lignes d'explication sur la façon dont il fonctionne avec des pointeurs pour mapper et filtrer la documentation le rendra parfait et clair pour les débutants
azakgaim
128

Vous pouvez utiliser une approche de dictionnaire comme celle-ci. Fondamentalement, vous attribuez la valeur que vous souhaitez être distincte comme clé dans le "dictionnaire" (ici, nous utilisons un tableau comme objet pour éviter le mode dictionnaire). Si la clé n'existait pas, vous ajoutez cette valeur comme distincte.

Voici une démo fonctionnelle:

var array = [{"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35}];
var unique = [];
var distinct = [];
for( let i = 0; i < array.length; i++ ){
  if( !unique[array[i].age]){
    distinct.push(array[i].age);
    unique[array[i].age] = 1;
  }
}
var d = document.getElementById("d");
d.innerHTML = "" + distinct;
<div id="d"></div>

Ce sera O (n) où n est le nombre d'objets dans le tableau et m est le nombre de valeurs uniques. Il n'y a pas de moyen plus rapide que O (n) car vous devez inspecter chaque valeur au moins une fois.

La version précédente de celui-ci utilisait un objet, et pour in. Celles-ci étaient de nature mineure et ont depuis été légèrement mises à jour ci-dessus. Cependant, la raison d'une apparente amélioration des performances entre les deux versions dans le jsperf d'origine était due à la petite taille de l'échantillon de données. Ainsi, la comparaison principale dans la version précédente portait sur la différence entre la carte interne et l'utilisation du filtre par rapport aux recherches en mode dictionnaire.

J'ai mis à jour le code ci-dessus, comme indiqué, cependant, j'ai également mis à jour le jsperf pour regarder à travers 1000 objets au lieu de 3. 3 négligé de nombreux pièges de performances impliqués ( jsperf obsolète ).

Performance

https://jsperf.com/filter-vs-dictionary-more-data Lorsque j'ai exécuté ce dictionnaire, il était 96% plus rapide.

filtre vs dictionnaire

Travis J
la source
4
rapide et sans aucun plugin supplémentaire requis. Vraiment cool
mihai
2
que diriez-vousif( typeof(unique[array[i].age]) == "undefined"){ distinct.push(array[i].age); unique[array[i].age] = 0; }
Timeless
7
Wow, les performances ont vraiment changé en faveur de l'option de carte. Cliquez sur ce lien jsperf!
AU
1
@ 98percentmonkey - L'objet a été utilisé pour faciliter "l'approche par dictionnaire". À l'intérieur de l'objet, chaque occurrence suivie est ajoutée sous forme de clé (ou de bac). De cette façon, lorsque nous rencontrons une occurrence, nous pouvons vérifier si la clé (ou le bac) existe; si elle existe, nous savons que l'occurrence n'est pas unique - si elle n'existe pas, nous savons que l'occurrence est unique et ajoutez-la.
Travis J
1
@ 98percentmonkey - La raison d'utiliser un objet est que la recherche est O (1) car elle vérifie une fois le nom d'une propriété, tandis qu'un tableau est O (n) car il doit regarder chaque valeur pour vérifier l'existence. À la fin du processus, le jeu de clés (bacs) dans l'objet représente le jeu d'occurrences uniques.
Travis J
92

Voici comment résoudre ce problème en utilisant le nouvel ensemble via ES6 pour Typescript à partir du 25 août 2017

Array.from(new Set(yourArray.map((item: any) => item.id)))
Christian Matthew
la source
3
cela a aidé, devenait avant merci. Le type 'Set' n'est pas un type de tableau
Robert King
1
C'est une excellente réponse. Jusqu'à ce que je défile vers celui-ci, j'allais écrire une réponse disant: Object.keys (values.reduce <any> ((x, y) => {x [y] = null; return x;}, {} )); Mais cette réponse est plus concise et s'applique à tous les types de données au lieu des seules chaînes.
jgosar
1
cette réponse est spectaculaire!
lukeocodes
80

En utilisant les fonctionnalités ES6, vous pourriez faire quelque chose comme:

const uniqueAges = [...new Set( array.map(obj => obj.age)) ];
Russell Vea
la source
6
Cette approche ne fonctionnera que sur les types primitifs (ce qui est le cas ici car les âges sont un tableau de nombres) mais échouera pour les objets.
k0pernikus
une idée comment le faire fonctionner pour les objets avec deux clés?
cegprakash
1
Quelque chose commeconst uniqueObjects = [ ...new Set( array.map( obj => obj.age) ) ].map( age=> { return array.find(obj => obj.age === age) } )
Harley B
62

Je mapperais et supprimerais les doublons:

var ages = array.map(function(obj) { return obj.age; });
ages = ages.filter(function(v,i) { return ages.indexOf(v) == i; });

console.log(ages); //=> [17, 35]

Edit: Aight! Pas le moyen le plus efficace en termes de performances, mais l'OMI le plus simple et le plus lisible. Si vous vous souciez vraiment de la micro-optimisation ou si vous avez d'énormes quantités de données, une forboucle régulière sera plus "efficace".

elclanrs
la source
3
@elclanrs - "le moyen le plus efficace en termes de performances" - Cette approche est lente .
Travis J
1
@Eevee: Je vois. La version de soulignement dans votre réponse n'est pas très rapide non plus , je veux dire, à la fin, vous choisissez ce qui est plus pratique, je doute que 1-30% reflète plus ou moins "une énorme amélioration" dans les tests génériques et lorsque les OP / s sont des milliers .
elclanrs
4
Et bien certainement. avec seulement trois éléments , le plus rapide est de faire trois variables et d'utiliser quelques ifs. vous obtiendrez des résultats très différents avec trois millions.
Evoli
1
pas rapide mais dans mon cas, cela a fait l'affaire car je n'ai pas affaire à un grand ensemble de données, merci.
Felipe Alarcon
37
var unique = array
    .map(p => p.age)
    .filter((age, index, arr) => arr.indexOf(age) == index)
    .sort(); // sorting is optional

// or in ES6

var unique = [...new Set(array.map(p => p.age))];

// or with lodash

var unique = _.uniq(_.map(array, 'age'));

Exemple ES6

const data = [
  { name: "Joe", age: 17}, 
  { name: "Bob", age: 17}, 
  { name: "Carl", age: 35}
];

const arr = data.map(p => p.age); // [17, 17, 35]
const s = new Set(arr); // {17, 35} a set removes duplications, but it's still a set
const unique = [...s]; // [17, 35] Use the spread operator to transform a set into an Array
// or use Array.from to transform a set into an array
const unique2 = Array.from(s); // [17, 35]
oleg gabureac
la source
6
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire sur la manière et la raison pour laquelle il résout le problème améliorerait la valeur à long terme de la réponse.
Alexander
Le premier qui utilise l'indexOf contre l'indice est tout simplement génial.
hélas
Notez que cela ne fonctionne que pour les valeurs primitives. Si vous avez un tableau de dates, vous avez besoin de méthodes plus personnalisées. En savoir plus ici: codeburst.io/javascript-array-distinct-5edc93501dc4
Molx
36

Pour ceux qui veulent retourner un objet avec toutes les propriétés uniques par clé

const array =
  [
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
  ]

const key = 'age';

const arrayUniqueByKey = [...new Map(array.map(item =>
  [item[key], item])).values()];

console.log(arrayUniqueByKey);

   /*OUTPUT
       [
        { "name": "Bob", "age": 17 },
        { "name": "Carl", "age": 35 }
       ]
   */

 // Note: this will pick the last duplicated item in the list.

Arun Kumar Saini
la source
2
Remarque: cela sélectionnera le dernier élément dupliqué dans la liste.
Eugene Kulabuhov
1
Ajoutant cela à la réponse!
Arun Kumar Saini
1
Exactement ce que je cherchais. Merci beaucoup pour le partage!
Devner
1
Je pense que cela devrait être la meilleure réponse pour être honnête!
Jaroslav Benc
26

Il existe déjà de nombreuses réponses valides, mais je voulais en ajouter une qui utilise uniquement la reduce()méthode car elle est propre et simple.

function uniqueBy(arr, prop){
  return arr.reduce((a, d) => {
    if (!a.includes(d[prop])) { a.push(d[prop]); }
    return a;
  }, []);
}

Utilisez-le comme ceci:

var array = [
  {"name": "Joe", "age": 17}, 
  {"name": "Bob", "age": 17}, 
  {"name": "Carl", "age": 35}
];

var ages = uniqueBy(array, "age");
console.log(ages); // [17, 35]
Harry Stevens
la source
20

La forEachversion de la réponse de @ travis-j (utile sur les navigateurs modernes et le monde Node JS):

var unique = {};
var distinct = [];
array.forEach(function (x) {
  if (!unique[x.age]) {
    distinct.push(x.age);
    unique[x.age] = true;
  }
});

34% plus rapide sur Chrome v29.0.1547: http://jsperf.com/filter-versus-dictionary/3

Et une solution générique qui prend une fonction de mappeur (un peu plus lente que la carte directe, mais c'est prévu):

function uniqueBy(arr, fn) {
  var unique = {};
  var distinct = [];
  arr.forEach(function (x) {
    var key = fn(x);
    if (!unique[key]) {
      distinct.push(key);
      unique[key] = true;
    }
  });
  return distinct;
}

// usage
uniqueBy(array, function(x){return x.age;}); // outputs [17, 35]
Mrchief
la source
1
J'aime mieux la solution générique car il est peu probable que l'âge soit la seule valeur distincte nécessaire dans un scénario réel.
Toft
5
Dans le générique, changez "distinct.push (clé)" en "distinct.push (x)" pour renvoyer une liste des éléments réels, que je trouve très utilisables!
Silas Hansen
15

J'ai commencé à coller Underscore dans tous les nouveaux projets par défaut, donc je n'ai jamais à penser à ces petits problèmes de transfert de données.

var array = [{"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35}];
console.log(_.chain(array).map(function(item) { return item.age }).uniq().value());

Produit [17, 35].

Évoli
la source
13

Voici une autre façon de résoudre ce problème:

var result = {};
for(var i in array) {
    result[array[i].age] = null;
}
result = Object.keys(result);

Je ne sais pas à quelle vitesse cette solution est comparée aux autres, mais j'aime le look plus propre. ;-)


EDIT: D'accord, ce qui précède semble être la solution la plus lente de toutes ici.

J'ai créé un cas de test de performance ici: http://jsperf.com/distinct-values-from-array

Au lieu de tester pour les âges (Integers), j'ai choisi de comparer les noms (Strings).

La méthode 1 (solution de TS) est très rapide. Chose intéressante, la méthode 7 surpasse toutes les autres solutions, ici je viens de me débarrasser de .indexOf () et j'en ai utilisé une implémentation "manuelle", en évitant les appels en boucle:

var result = [];
loop1: for (var i = 0; i < array.length; i++) {
    var name = array[i].name;
    for (var i2 = 0; i2 < result.length; i2++) {
        if (result[i2] == name) {
            continue loop1;
        }
    }
    result.push(name);
}

La différence de performances avec Safari et Firefox est incroyable, et il semble que Chrome fasse le meilleur travail d'optimisation.

Je ne sais pas exactement pourquoi les extraits ci-dessus sont si rapides par rapport aux autres, peut-être que quelqu'un de plus sage que moi a une réponse. ;-)

BaM
la source
10

utilisant lodash

var array = [
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
];
_.chain(array).pluck('age').unique().value();
> [17, 35]
Ivan Nosov
la source
2
Pouvez-vous expliquer comment faire cela avec du javascript simple comme cela est impliqué dans la question?
Ruskin
c'est une fonction de soulignement _.chain
vini
2
mais pluck () n'est pas dans lodash.
Yash Vekaria
1
_.chain (array) .map ('age'). unique (). value (); travaillé pour moi.
Yash Vekaria
la version 4.0 a connu quelques changements de rupture - stackoverflow.com/a/31740263/4050261
Adarsh ​​Madrecha
7

Utiliser Lodash

var array = [
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
];

_.chain(array).map('age').unique().value();

Renvoie [17,35]

Yash Vekaria
la source
6
function get_unique_values_from_array_object(array,property){
    var unique = {};
    var distinct = [];
    for( var i in array ){
       if( typeof(unique[array[i][property]]) == "undefined"){
          distinct.push(array[i]);
       }
       unique[array[i][property]] = 0;
    }
    return distinct;
}
Dmitriy Kupriyanov
la source
5

underscore.js _.uniq(_.pluck(array,"age"))

Radosław Kopczyński
la source
5
Veuillez ajouter une explication de la façon dont cela répond à la question.
Robotic Cat
2
_.pluck a été supprimé au profit de _.map
Ajax3.14
5

Voici une solution polyvalente qui utilise réduire, permet le mappage et maintient l'ordre d'insertion.

éléments : un tableau

mapper : fonction unaire qui mappe l'élément aux critères, ou vide pour mapper l'élément lui-même.

function distinct(items, mapper) {
    if (!mapper) mapper = (item)=>item;
    return items.map(mapper).reduce((acc, item) => {
        if (acc.indexOf(item) === -1) acc.push(item);
        return acc;
    }, []);
}

Usage

const distinctLastNames = distinct(items, (item)=>item.lastName);
const distinctItems = distinct(items);

Vous pouvez l'ajouter à votre prototype Array et laisser de côté le paramètre items si c'est votre style ...

const distinctLastNames = items.distinct( (item)=>item.lastName) ) ;
const distinctItems = items.distinct() ;

Vous pouvez également utiliser un ensemble au lieu d'un tableau pour accélérer la correspondance.

function distinct(items, mapper) {
    if (!mapper) mapper = (item)=>item;
    return items.map(mapper).reduce((acc, item) => {
        acc.add(item);
        return acc;
    }, new Set());
}
Steven Spungin
la source
5

const x = [
  {"id":"93","name":"CVAM_NGP_KW"},
  {"id":"94","name":"CVAM_NGP_PB"},
  {"id":"93","name":"CVAM_NGP_KW"},
  {"id":"94","name":"CVAM_NGP_PB"}
].reduce(
  (accumulator, current) => accumulator.some(x => x.id === current.id)? accumulator: [...accumulator, current ], []
)

console.log(x)

/* output 
[ 
  { id: '93', name: 'CVAM_NGP_KW' },
  { id: '94', name: 'CVAM_NGP_PB' } 
]
*/

Ruben Morales Felix
la source
2
cela ressemble à O (n ^ 2)
cegprakash
4

Je viens de le trouver et je l'ai trouvé utile

_.map(_.indexBy(records, '_id'), function(obj){return obj})

Encore une fois en utilisant le soulignement , donc si vous avez un objet comme celui-ci

var records = [{_id:1,name:'one', _id:2,name:'two', _id:1,name:'one'}]

il vous donnera uniquement les objets uniques.

Ce qui se passe ici, c'est que indexByrenvoie une carte comme celle-ci

{ 1:{_id:1,name:'one'}, 2:{_id:2,name:'two'} }

et juste parce que c'est une carte, toutes les clés sont uniques.

Ensuite, je mappe simplement cette liste sur le tableau.

Si vous n'avez besoin que des valeurs distinctes

_.map(_.indexBy(records, '_id'), function(obj,key){return key})

Gardez à l'esprit que le keyest retourné sous forme de chaîne, donc si vous avez besoin d'entiers à la place, vous devriez faire

_.map(_.indexBy(records, '_id'), function(obj,key){return parseInt(key)})
simo
la source
4

je pense que vous recherchez la fonction groupBy (en utilisant Lodash)

_personsList = [{"name":"Joe", "age":17}, 
                {"name":"Bob", "age":17}, 
                {"name":"Carl", "age": 35}];
_uniqAgeList = _.groupBy(_personsList,"age");
_uniqAges = Object.keys(_uniqAgeList);

produit un résultat:

17,35

Démo jsFiddle: http://jsfiddle.net/4J2SX/201/

Amil Sajeev
la source
3

Si, comme moi, vous préférez une version plus "fonctionnelle" sans compromettre la vitesse, cet exemple utilise une recherche rapide de dictionnaire enveloppée à l'intérieur pour réduire la fermeture.

var array = 
[
    {"name":"Joe", "age":17}, 
    {"name":"Bob", "age":17}, 
    {"name":"Carl", "age": 35}
]
var uniqueAges = array.reduce((p,c,i,a) => {
    if(!p[0][c.age]) {
        p[1].push(p[0][c.age] = c.age);
    }
    if(i<a.length-1) {
        return p
    } else {
        return p[1]
    }
}, [{},[]])

Selon ce test, ma solution est deux fois plus rapide que la réponse proposée

bmaggi
la source
3
[...new Set([
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
  ].map(({ age }) => age))]
Marian Zburlea
la source
3

Je sais que mon code est peu long et peu complexe, mais il est compréhensible, j'ai donc essayé de cette façon.

J'essaie de développer ici une fonction basée sur un prototype et le code change également.

Ici, Distinct est ma propre fonction prototype.

<script>
  var array = [{
      "name": "Joe",
      "age": 17
    },
    {
      "name": "Bob",
      "age": 17
    },
    {
      "name": "Carl",
      "age": 35
    }
  ]

  Array.prototype.Distinct = () => {
    var output = [];
    for (let i = 0; i < array.length; i++) {
      let flag = true;
      for (let j = 0; j < output.length; j++) {
        if (array[i].age == output[j]) {
          flag = false;
          break;
        }
      }
      if (flag)
        output.push(array[i].age);
    }
    return output;
  }
  //Distinct is my own function
  console.log(array.Distinct());
</script>

Prabhat
la source
2

Si vous avez Array.prototype.includes ou êtes prêt à le polyfill , cela fonctionne:

var ages = []; array.forEach(function(x) { if (!ages.includes(x.age)) ages.push(x.age); });
briseur de plume
la source
1

Mon code ci-dessous affichera le tableau unique des âges ainsi que le nouveau tableau n'ayant pas d'âge en double

var data = [
  {"name": "Joe", "age": 17}, 
  {"name": "Bob", "age": 17}, 
  {"name": "Carl", "age": 35}
];

var unique = [];
var tempArr = [];
data.forEach((value, index) => {
    if (unique.indexOf(value.age) === -1) {
        unique.push(value.age);
    } else {
        tempArr.push(index);    
    }
});
tempArr.reverse();
tempArr.forEach(ele => {
    data.splice(ele, 1);
});
console.log('Unique Ages', unique);
console.log('Unique Array', data);```
Shridhar Sagari
la source
1

J'ai écrit le mien en TypeScript, pour un cas générique, comme celui de Kotlin Array.distinctBy {}...

function distinctBy<T, U extends string | number>(array: T[], mapFn: (el: T) => U) {
  const uniqueKeys = new Set(array.map(mapFn));
  return array.filter((el) => uniqueKeys.has(mapFn(el)));
}

Uest lavable, bien sûr. Pour les objets, vous pourriez avoir besoin de https://www.npmjs.com/package/es6-json-stable-stringify

Polv
la source
1

Si vous avez besoin d'un objet unique

const _ = require('lodash');

var objects = [
  { 'x': 1, 'y': 2 },
  { 'y': 1, 'x': 2 },
  { 'x': 2, 'y': 1 },
  { 'x': 1, 'y': 2 }
];

_.uniqWith(objects, _.isEqual);

[Objet {x: 1, y: 2}, Objet {x: 2, y: 1}]

cegprakash
la source
downvoter: Vous voulez expliquer pourquoi le downvote?
cegprakash
1

Répondre à cette vieille question est assez inutile, mais il existe une réponse simple qui parle de la nature de Javascript. Les objets en Javascript sont intrinsèquement des tables de hachage. Nous pouvons l'utiliser pour obtenir un hachage de clés uniques:

var o = {}; array.map(function(v){ o[v.age] = 1; });

Ensuite, nous pouvons réduire le hachage à un tableau de valeurs uniques:

var a2 = []; for (k in o){ a2.push(k); }

C'est tout ce dont vous avez besoin. Le tableau a2 contient uniquement les âges uniques.

Preston L. Bannister
la source
1

Une doublure simple avec de grandes performances. 6% plus rapide que les solutions ES6 dans mes tests .

var ages = array.map(function(o){return o.age}).filter(function(v,i,a) {
    return a.indexOf(v)===i
});
Craig
la source
@ Jeb50 Care pour ajouter une multi-ligne facile à lire? En regardant les autres ici, je ne pense vraiment pas qu'ils soient faciles à lire ou à comprendre. Je pense qu'il est préférable de placer cela dans une fonction qui décrit ce qu'il fait.
Craig
2
Avec des fonctions de direction: array.map( o => o.age).filter( (v,i,a) => a.indexOf(v)===i). J'utiliser le mot - clé de fonction si rarement maintenant que je dois lire des choses deux fois quand je le vois 😊
Drenai