J'apprends JS. Supposons que j'ai le tableau ci-dessous d'objets:
var family = [
{
name: "Mike",
age: 10
},
{
name: "Matt"
age: 13
},
{
name: "Nancy",
age: 15
},
{
name: "Adam",
age: 22
},
{
name: "Jenny",
age: 85
},
{
name: "Nancy",
age: 2
},
{
name: "Carl",
age: 40
}
];
Notez que Nancy apparaît deux fois (ne change que l'âge). Supposons que je veuille produire uniquement des noms uniques. Comment puis-je sortir le tableau d'objets ci-dessus, sans les dupliquer? ES6 répond plus que bienvenu.
Relatif (impossible de trouver un bon moyen d'utilisation sur les objets):
EDIT Voici ce que j'ai essayé. Cela fonctionne bien avec les chaînes mais je ne vois pas comment le faire fonctionner avec des objets:
family.reduce((a, b) => {
if (a.indexOf(b) < 0 ) {
a.Push(b);
}
return a;
},[]);
Vous pouvez utiliser Set
en combinaison avec Array#map
et un opérateur spread...
sur une seule ligne.
Map renvoie un tableau avec tous les noms, qui vont dans l'initialiseur de l'ensemble, puis toutes les valeurs de l'ensemble sont renvoyées dans un tableau.
var family = [{ name: "Mike", age: 10 }, { name: "Matt", age: 13 }, { name: "Nancy", age: 15 }, { name: "Adam", age: 22 }, { name: "Jenny", age: 85 }, { name: "Nancy", age: 2 }, { name: "Carl", age: 40 }],
unique = [...new Set(family.map(a => a.name))];
console.log(unique);
Pour filtrer et renvoyer uniquement des noms uniques, vous pouvez utiliser Array#filter
avec Set
.
var family = [{ name: "Mike", age: 10 }, { name: "Matt", age: 13 }, { name: "Nancy", age: 15 }, { name: "Adam", age: 22 }, { name: "Jenny", age: 85 }, { name: "Nancy", age: 2 }, { name: "Carl", age: 40 }],
unique = family.filter((set => f => !set.has(f.name) && set.add(f.name))(new Set));
console.log(unique);
Stocker les occurrences de name
externes à la boucle dans un objet et filtrer les occurrences précédentes.
https://jsfiddle.net/nputptbb/2/
var occurrences = {}
var filteredFamily = family.filter(function(x) {
if (occurrences[x.name]) {
return false;
}
occurrences[x.name] = true;
return true;
})
vous pouvez aussi généraliser cette solution à une fonction
function filterByProperty(array, propertyName) {
var occurrences = {}
return array.filter(function(x) {
var property = x[propertyName]
if (occurrences[property]) {
return false;
}
occurrences[property]] = true;
return true;
})
}
et l'utiliser comme
var filteredFamily = filterByProperty(family, 'name')
Ne comparez pas les objets avec indexOf
, qui utilise uniquement l'opérateur ===
entre les objets. La raison pour laquelle votre réponse actuelle ne fonctionne pas est que ===
dans JS ne compare pas les objets en profondeur, mais compare les références. Ce que je veux dire par là, vous pouvez voir dans le code suivant:
var a = { x: 1 }
var b = { x: 1 }
console.log(a === b) // false
console.log(a === a) // true
Equality vous dira si vous avez trouvé l'objet same exact, mais pas si vous avez trouvé un objet avec le même contenu.
Dans ce cas, vous pouvez comparer votre objet sur name
car il doit s'agir d'une clé unique. Donc, obj.name === obj.name
au lieu de obj === obj
. De plus, un autre problème avec votre code qui affecte son exécution et non sa fonction est que vous utilisez un indexOf
dans votre reduce
. indexOf
est O(n)
, ce qui rend la complexité de votre algorithme O(n^2)
. Il est donc préférable d’utiliser un objet qui a la fonction O(1)
lookup.
Cela fonctionnera bien.
[1, 2, 2, 3, 3, 3, 3].reduce((x, y) => x.includes(y) ? x : [...x, y], [])
Je viens de penser à 2 façons simples pour les utilisateurs de Lodash
Étant donné ce tableau:
let family = [
{
name: "Mike",
age: 10
},
{
name: "Matt",
age: 13
},
{
name: "Nancy",
age: 15
},
{
name: "Adam",
age: 22
},
{
name: "Jenny",
age: 85
},
{
name: "Nancy",
age: 2
},
{
name: "Carl",
age: 40
}
]
1. Trouver des doublons:
let duplicatesArr = _.difference(family, _.uniqBy(family, 'name'), 'name')
// duplicatesArr:
// [{
// name: "Nancy",
// age: 2
// }]
2 Recherchez s'il y a des doublons, à des fins de validation:
let uniqArr = _.uniqBy(family, 'name')
if (uniqArr.length === family.length) {
// No duplicates
}
if (uniqArr.length !== family.length) {
// Has duplicates
}
Avec le code que vous avez mentionné, vous pouvez essayer:
family.filter((item, index, array) => {
return array.map((mapItem) => mapItem['name']).indexOf(item['name']) === index
})
Ou vous pouvez avoir une fonction générique pour le faire fonctionner pour d'autres tableaux d'objets:
function printUniqueResults (arrayOfObj, key) {
return arrayOfObj.filter((item, index, array) => {
return array.map((mapItem) => mapItem[key]).indexOf(item[key]) === index
})
}
et puis utilisez simplement printUniqueResults(family, 'name')