Maison > interface Web > js tutoriel > Compter les choses en Javascript

Compter les choses en Javascript

WBOY
Libérer: 2024-08-08 07:17:32
original
689 Les gens l'ont consulté

Counting things in Javascript

Si vous souhaitez compter le nombre d'éléments d'une variété spécifique dans un tableau, vous pouvez filtrer ce tableau et vérifier la longueur du résultat.

const letters = ['a','b','b','c','c','c'];
const numberOfC = letters.filter(letter => letter === 'c').length;
console.log(numberOfC); // 3
Copier après la connexion

Cela a une complexité temporelle de O(n), qui est l'idéal théorique pour ce type de problème. Il utilise de la mémoire supplémentaire pour contenir un deuxième tableau, mais pour ne compter qu'une seule variété d'éléments, il s'agit d'une approche courante et suffisamment efficace dans la plupart des situations. Cependant, ce n'est pas une approche efficace si vous souhaitez compter toutes les variétés d'éléments du tableau.

Le problème avec le filtre

Si nous voulions compter non seulement le « c » mais aussi chaque lettre du tableau, l'application naïve de cette technique ressemblerait à ceci :

const letters = ['a','b','b','c','c','c'];
letters.forEach((letter, _, arr) => {
   const count = arr.filter(otherLetter => otherLetter === letter).length;
   console.log(letter, count);
});
Copier après la connexion

Cela produit le résultat suivant :

a 1
b 2
b 2
c 3
c 3
c 3
Copier après la connexion

Les décomptes sont corrects, mais il y a une redondance, qui peut être corrigée en utilisant d'abord un Set.

const letters = ['a','b','b','c','c','c'];
const uniqueLetters = new Set(letters);
for(const letter of uniqueLetters){
   const count = letters.filter(otherLetter => otherLetter === letter).length;
   console.log(letter, count);
};
Copier après la connexion

La sortie résultante n'a aucun doublon :

a 1
b 2
c 3
Copier après la connexion

Cependant, il a une complexité temporelle de O(n^2), car chaque filtre parcourt l'ensemble du tableau, et il doit le faire pour chaque lettre unique.

Une approche plus efficace

Il est possible d'effectuer ce décompte avec une complexité temporelle O(n). Le principe général est de parcourir le tableau une seule fois. Pour chaque élément rencontré, vérifiez si vous disposez déjà d’un décompte pour cet élément. Si vous le faites, incrémentez-le de 1. Si vous ne le faites pas, ajoutez un nombre pour cet élément avec une valeur définie sur 1.

Javascript dispose de deux mécanismes différents adaptés au stockage des décomptes. Nous pouvons utiliser des objets ou des cartes. Notez qu'il s'agit d'une référence à la structure de données Map et non à la méthode map() des tableaux. Utiliser une carte est plus efficace, mais utiliser des objets pour cela est encore assez courant, nous verrons donc comment compter avec les deux.

Compter avec une carte

const letters = ['a','b','b','c','c','c'];
const counts = new Map(); // Creates an empty Map
letters.forEach(letter => {
    if(counts.has(letter)) {//Determine if the letter already has a count
        counts.set(letter, counts.get(letter) + 1);//Increment existing count
    }
    else counts.set(letter, 1);//Set new count to 1
});
console.log(counts); //Map(3) { 'a' => 1, 'b' => 2, 'c' => 3 }
Copier après la connexion

Le has() vérifie si la valeur est déjà dans la carte. Le set() stocke une valeur dans la carte, soit en créant une nouvelle valeur, soit en écrasant une valeur existante. Le get() obtient la valeur actuelle. Notez que has(), set() et get() ont une complexité temporelle O(1), car un hachage est utilisé en interne.

Si nous voulions extraire plus tard le nombre de lettres spécifiques, nous pourrions faire quelque chose comme :

console.log(counts.get('c'));//3
Copier après la connexion

Compter avec un objet

Bien que compter avec des objets soit plus lent, la différence de performances peut ne pas être perceptible si vous ne comptez pas une énorme quantité d'objets. Les objets sont également mieux pris en charge par le navigateur que Maps, bien que cette différence soit devenue presque sans conséquence à ce stade. Selon caniuse.com, Map est pris en charge dans 96,28 % des navigateurs au moment d'écrire ces lignes. Les objets font partie intégrante du langage Javascript et devraient être pris en charge à 100 % par le navigateur, mais caniuse.com n'a pas de liste pour cela. La principale raison pour apprendre à utiliser des objets pour les décomptes est qu’il existe de nombreux anciens codes utilisant cette technique. Certaines personnes qui ont appris de l'ancien code écrivent également du nouveau code en utilisant cette approche.

const letters = ['a','b','b','c','c','c'];
const counts = {};//Create empty object for holding counts
letters.forEach(letter => {
    if(letter in counts) {//Check if the count exists
        counts[letter]++;//Increment the count
    }
    else counts[letter] = 1;//Set new count to 1
});
console.log(counts);//{ a: 1, b: 2, c: 3 }
Copier après la connexion

Ce code suit la même structure que le code utilisant une Map. Les différences résident dans la syntaxe des cartes et des objets. Le mot-clé "in" est utilisé pour tester si l'objet possède une clé portant ce nom. La syntaxe entre crochets est utilisée à la fois pour obtenir et définir les valeurs. Notez que tester l'appartenance, définir et obtenir des valeurs à partir d'un objet sont des opérations de complexité temporelle O(1), car les objets utilisent en interne un hachage pour les clés.

Le problème du comptage des objets

Si les choses que vous comptez sont des objets, des précautions supplémentaires sont nécessaires. Les cartes sont capables de stocker des objets sous forme de clés et préservent le type, mais cela crée un problème de comparaison d'égalité si vous avez un objet totalement différent qui a exactement les mêmes clés et valeurs.

const m = new Map();
m.set({name: "John"}, 5);
console.log(m.has({name: "John"}));//false
Copier après la connexion

Ce code renvoie "false", car les deux objets n'ont pas d'égalité référentielle. Les deux objets sont identiques en termes de clés et de valeurs, mais ce ne sont pas exactement le même objet.

const m = new Map();
const obj = {name: "John"}
m.set(obj, 5);
console.log(m.has(obj));//true
Copier après la connexion

Cette version du code renvoie « vrai », car la valeur définie est exactement le même objet dont l'adhésion est testée.

Le résultat d'essayer de compter les objets avec Maps dans la plupart des cas est que tous les objets finiront avec un compte de 1, car chaque has() renvoie false.

L'utilisation d'objets pour compter des objets pose un problème connexe mais légèrement différent. Les clés d'objet sont automatiquement contraintes à la chaîne (Sauf lorsqu'il s'agit de symboles). Si vous essayez d'utiliser un objet comme clé d'un autre objet, ce type de coercition crée une clé égale à "[object Object]".

const obj = {name: "John"}
const count = {};
count[obj] = 5;
console.log(count);// { '[object Object]': 5 }
Copier après la connexion

The result of trying to count objects using objects is you will end up with an object that has "[object Object]" as the key, and the value will be the total number of all the things that were counted. There won't be any individual counts, because every item is treated as "[object Object]".

How to count objects

It is not common that you would need to count objects. If the need arises, the solution depends on whether or not the objects have a unique property that is guaranteed to be unique. For example, objects that have an id number could be counted by counting the id number occurrences instead of counting occurrences of the whole object.

const employees = [
    {id: 1, name: "John"},
    {id: 1, name: "John"},
    {id: 2, name: "Mary"},
    {id: 2, name: "Mary"},
    {id: 2, name: "Mary"},
]
const counts = new Map();
employees.forEach(employee => {
    if(counts.has(employee.id)) {
        counts.set(employee.id, counts.get(employee.id) + 1);
    }
    else counts.set(employee.id, 1);
});
console.log(counts);//Map(2) { 1 => 2, 2 => 3 }
Copier après la connexion

This only gives counts with ids and an extra lookup would be needed to associate the counts with names, but we can fix that with a bit more code:

const countsWithNames = [];
for(const count of counts) {
    const employee = employees.find((employee) => employee.id === count[0]);
    countsWithNames.push({employee, count: count[1]});
}
console.log(countsWithNames);
Copier après la connexion

The resulting output is:

[
  { employee: { id: 1, name: 'John' }, count: 2 },
  { employee: { id: 2, name: 'Mary' }, count: 3 }
]
Copier après la connexion

If there isn't anything like an id that guarantees uniqueness, the only remaining practical option would be to first convert the object to JSON.

const people = [
    {name: "John Doe", age: 25},
    {name: "John Doe", age: 25},
    {name: "Mary Jane", age: 24},
    {name: "Mary Jane", age: 24},
    {name: "Mary Jane", age: 24}
]
const counts = new Map();
people.forEach(person => {
    const personString = JSON.stringify(person);
    if(counts.has(personString)) {
        counts.set(personString, counts.get(personString) + 1);
    }
    else counts.set(personString, 1);
});
console.log(counts);
Copier après la connexion

The resulting output is:

Map(2) {
  '{"name":"John Doe","age":25}' => 2,
  '{"name":"Mary Jane","age":24}' => 3
}
Copier après la connexion

Note that there are limitations to this approach. For example, objects with circular references cannot be stringified using JSON.stringify().

Counting non-array items

Both the techniques for counting with Maps and for counting with objects can be used to count anything, as long as you can find a way to iterate through the items. Some types of data can be converted to an array, for example, strings can be split, and keys of objects can be accessed as an array via Object.keys().

There are also some iterables that don't need to be converted into an array. For example, it's possible to iterate through the characters of a string by using an index. The same principle can be used in array-like structures like HTML Collections.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal