Travailler avec un tableau d'objets comme:
[ ["Car Wash Drops (0)", 400], ["Personal/Seeding (1)", 48], ["Personal/Seeding (2)", 48], ]
Je souhaite mapper
vers un tableau avec un identifiant supplémentaire pour les valeurs en double:
data.map((d, i) => [`${d.value} ${i}`, d.count]);
Jusqu'à présent, j'ai une fonction de carte pour mapper les valeurs en conséquence, mais je ne sais pas comment procéder pour ajouter l'identifiant uniquement pour les doublons.
[ ["Car Wash Drops", 400], ["Personal/Seeding", 48], ["Personal/Seeding", 48], ]
donne:
data.map(d => [`${d.value}`, d.count]);
J'ai également utilisé l'index avec, mais il ajoute l'index sur chaque valeur:
const expected = [ ["Car Wash Drops", 400], ["Personal/Seeding (1)", 48], ["Personal/Seeding (2)", 48], ];
4 Réponses :
Vous pouvez passer un deuxième argument à .map ()
après le rappel. Cette valeur sera utilisée comme valeur de this
lorsque le rappel est appelé. Ainsi, vous pouvez passer par un objet que vous pouvez utiliser pour accumuler un nombre de répétitions:
data.map(function(d, i) { if (!(d.value in this)) this[d.value] = 0; else this[d.value] += 1; return [ d.value + (this[d.value] ? " (" + this[d.value] + ")" : ""), d.count ]; }, {});
En commençant par un objet vide, le rappel peut garder une trace du nombre de fois où il est vu chaque chaîne d.value
. Lorsqu'il voit une répétition, il peut ajouter le qualificatif à la chaîne.
Maintenant, cela ne fait pas exactement ce que vous avez demandé, car il ne regarde qu'une seule valeur à un temps. Ainsi, la première fois qu'il voit "Personal / Seeding"
, il ne sait pas que c'est un doublon, donc il n'est pas modifié avec le qualificatif. La deuxième fois, c'est bien sûr.
Faire ce que vous avez demandé, si cela ne suffit pas, nécessiterait d'abord un passage complet dans le tableau pour obtenir un décompte final des doublons pour chaque chaîne.
Vous pouvez gérer une correspondance entre les valeurs que vous avez vues et le nombre d'entre elles que vous avez vues. Ensuite, il sera plus facile d'obtenir le bon numéro en fonction de la présence ou non d'un doublon:
const data = [ {count: 400, value: "Car Wash Drops"}, {count: 48, value: "Personal/Seeding"}, {count: 48, value: "Personal/Seeding"}, ]; let valueCounts = data.reduce((a, c) => { a[c.value] = a[c.value] || {current: 1, total: 0}; a[c.value].total += 1; return a; }, {}); const expected = data.map(({count, value}) => { if (valueCounts[value].total === 1) return [value, count]; return [`${value} (${valueCounts[value].current++})`, count]; }); console.log(expected);
En utilisant votre approche, vous pouvez utiliser filter ()
à l'intérieur de la carte pour vérifier combien d'éléments sur le tableau d'origine ont la même valeur que celui analysé en cours, en utilisant cette condition, vous pouvez choisir quoi renvoie comme nouvelle valeur:
const data = [ {count: 400, value: "Car Wash Drops"}, {count: 48, value: "Personal/Seeding"}, {count: 48, value: "Personal/Seeding"}, {count: 300, value: "Operators/Management"}, {count: 48, value: "Personal/Seeding"} ]; let counters = data.reduce((res, {value}) => { res.set(value, res.has(value) ? res.get(value) + 1 : 1); return res; }, new Map()); let res = data.map((x, idx) => { return [ `${x.value}` + (counters.get(x.value) > 1 ? `(${idx})` : ""), x.count ]; }); console.log(res);
Les performances de l'approche précédente pourraient être améliorées si nous utilisons some ()
au lieu de filter ()
, comme ceci:
const data = [ {count: 400, value: "Car Wash Drops"}, {count: 48, value: "Personal/Seeding"}, {count: 48, value: "Personal/Seeding"}, {count: 300, value: "Operators/Management"}, {count: 48, value: "Personal/Seeding"} ]; let res = data.map((x, idx) => { if (data.some((y, j) => y.value === x.value && idx !== j)) return [`${x.value} (${idx})`, x.count]; else return [`${x.value}`, x.count]; }); console.log(res);
Et pourrait être amélioré encore plus si nous créons auparavant un Carte avec le compteur de fois qu'un élément apparaît dans le tableau d'origine. Comme ceci:
const data = [ {count: 400, value: "Car Wash Drops"}, {count: 48, value: "Personal/Seeding"}, {count: 48, value: "Personal/Seeding"}, ]; let res = data.map((x, idx) => { if (data.filter(y => y.value === x.value).length > 1) return [`${x.value} (${idx})`, x.count]; else return [`${x.value}`, x.count]; }); console.log(res);
Il convient de noter qu'il s'agit d'un processus O (n ^ 2), donc cela coûterait cher si le tableau était beaucoup plus long.
La réponse a déjà été donnée, avec tout le respect que je dois à l'auteur de la réponse, je pense que certaines améliorations pourraient être apportées à la réponse, à la fois syntaxiquement et en termes de performances:
réduire
doit être évité si la source est très grande, bien que je préfère toujours réduire
si la source est relativement petite (data.length POF (purement ancien pour :)) car c'est l'option la plus rapide.
La carte ES6 est une aide précieuse lorsque nous traitons des paires clé-valeur , mais je préfère POO (simple objet ancien :) ) si c'est le cas possible et cela rendra notre code plus esthétique.
Je vais fournir ma solution au problème (il exécutera O (n) et utilisera un espace O (n) supplémentaire pour les paires clé-valeur dans le pire des cas, il fera deux passes sur la source donc , le deuxième passage est nécessaire pour mettre 1 là où nous avons manqué lors de notre première rencontre):
let data = [ {count: 400, value: "Car Wash Drops"}, {count: 48, value: "Personal/Seeding"}, {count: 48, value: "Personal/Seeding"}, {count: 300, value: "Operators/Management"}, {count: 48, value: "Personal/Seeding"} ]; const map = {}; for (let d of data) { map[d.value] = map[d.value]+1 || 0; d.value = map[d.value]?d.value+` (${map[d.value]+1})`:d.value; } for (let d of data) { d.value = map[d.value]?d.value+` (1)`:d.value; } console.log(data.map(o=>[o.value,o.count]));
Ou une version plus concise utilisant l'opérateur ES6 of
[lien vers de] :
let data = [ {count: 400, value: "Car Wash Drops"}, {count: 48, value: "Personal/Seeding"}, {count: 48, value: "Personal/Seeding"}, {count: 300, value: "Operators/Management"}, {count: 48, value: "Personal/Seeding"} ]; const map = {}; for (let i=0;i<data.length;i+=1) { map[ data[i].value ] = map[ data[i].value ]+1 || 0; data[i].value = map[data[i].value]?data[i].value+` (${map[data[i].value]+1})`:data[i].value; } for (let i=0;i<data.length;i+=1) { data[i].value = map[data[i].value]?data[i].value+` (1)`:data[i].value; } console.log(data.map(o=>[o.value,o.count]));
Je suggère de préciser que vous voulez l'index du tableau d'origine pour les éléments dupliqués, pas un compteur avec le nombre de fois que l'élément est présent.
Cette réponse peut être utile: stackoverflow.com/a/36744732/2266428 , car cette question a déjà été posée dans le passé et a de nombreuses réponses.
Double possible de Supprimer les doublons d'un tableau d'objets dans JavaScript a>