Heim >Web-Frontend >js-Tutorial >Dinge zählen in Javascript

Dinge zählen in Javascript

WBOY
WBOYOriginal
2024-08-08 07:17:32679Durchsuche

Counting things in Javascript

Wenn Sie zählen möchten, wie viele Elemente einer bestimmten Sorte sich in einem Array befinden, können Sie dieses Array filtern und die Länge des Ergebnisses überprüfen.

const letters = ['a','b','b','c','c','c'];
const numberOfC = letters.filter(letter => letter === 'c').length;
console.log(numberOfC); // 3

Dies hat eine zeitliche Komplexität von O(n), was dem theoretischen Ideal für diese Art von Problem entspricht. Es benötigt etwas zusätzlichen Speicher, um ein zweites Array zu speichern, aber um nur eine Art von Elementen zu zählen, ist dies ein gängiger Ansatz und in den meisten Situationen effizient genug. Dies ist jedoch kein effizienter Ansatz, wenn Sie die Anzahl aller Elemente im Array ermitteln möchten.

Das Problem mit dem Filter

Wenn wir nicht nur die Zählung von „c“, sondern von jedem Buchstaben im Array wünschen, würde die naive Anwendung dieser Technik etwa so aussehen:

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

Dies erzeugt die folgende Ausgabe:

a 1
b 2
b 2
c 3
c 3
c 3

Die Zählungen sind korrekt, es gibt jedoch Redundanzen, die behoben werden können, indem zunächst ein Set verwendet wird.

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);
};

Die resultierende Ausgabe enthält keine Duplikate:

a 1
b 2
c 3

Es hat jedoch eine zeitliche Komplexität von O(n^2), da jeder Filter das gesamte Array durchläuft und dies für jeden einzelnen Buchstaben tun muss.

Ein effizienterer Ansatz

Es ist möglich, diese Zählung mit O(n)-Zeitkomplexität durchzuführen. Das allgemeine Prinzip besteht darin, das Array nur einmal zu iterieren. Überprüfen Sie für jedes gefundene Element, ob Sie bereits eine Zählung für dieses Element haben. Wenn Sie dies tun, erhöhen Sie den Wert um 1. Wenn Sie dies nicht tun, fügen Sie eine Anzahl für dieses Element mit einem Wert von 1 hinzu.

Javascript verfügt über zwei verschiedene Mechanismen, die zum Speichern der Zählungen geeignet sind. Wir können Objekte oder Karten verwenden. Beachten Sie, dass es sich dabei um einen Verweis auf die Map-Datenstruktur handelt und nicht um die Methode „map()“ von Arrays. Die Verwendung einer Karte ist effizienter, aber die Verwendung von Objekten hierfür ist immer noch weit verbreitet, daher werden wir uns ansehen, wie man mit beiden zählt.

Zählen mit einer Karte

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 }

has() prüft, ob der Wert bereits in der Map vorhanden ist. Das set() speichert einen Wert in der Map und erstellt entweder einen neuen Wert oder überschreibt einen vorhandenen. get() ruft den aktuellen Wert ab. Beachten Sie, dass has(), set() und get() eine Zeitkomplexität von O(1) haben, da intern ein Hash verwendet wird.

Wenn wir später die Anzahl eines bestimmten Buchstabens extrahieren wollten, könnten wir so etwas tun:

console.log(counts.get('c'));//3

Mit einem Objekt zählen

Obwohl das Zählen mit Objekten langsamer ist, ist der Leistungsunterschied möglicherweise nicht spürbar, wenn Sie nicht eine große Menge an Elementen zählen. Objekte bieten außerdem mehr Browserunterstützung als Karten, obwohl dieser Unterschied zu diesem Zeitpunkt fast keine Rolle mehr spielt. Laut caniuse.com wird Map zum Zeitpunkt des Verfassens dieses Artikels in 96,28 % der Browser unterstützt. Objekte sind ein integraler Bestandteil der Javascript-Sprache und sollten eine 100-prozentige Browserunterstützung bieten, aber caniuse.com hat keinen Eintrag dafür. Der Hauptgrund für das Erlernen der Verwendung von Objekten für Zählungen liegt darin, dass es viele alte Codes gibt, die diese Technik verwenden. Einige Leute, die aus altem Code gelernt haben, schreiben mit diesem Ansatz auch neuen Code.

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 }

Dieser Code folgt der gleichen Struktur wie der Code, der eine Karte verwendet. Die Unterschiede bestehen in der Syntax für Karten und Objekte. Das Schlüsselwort „in“ wird verwendet, um zu testen, ob das Objekt einen Schlüssel mit diesem Namen hat. Die Klammersyntax wird sowohl zum Abrufen als auch zum Festlegen der Werte verwendet. Beachten Sie, dass das Testen der Mitgliedschaft, das Festlegen und das Abrufen von Werten von einem Objekt O(1)-Zeitkomplexitätsoperationen sind, da Objekte intern einen Hash für die Schlüssel verwenden.

Das Problem des Zählens von Objekten

Wenn es sich bei den Dingen, die Sie zählen, um Gegenstände handelt, ist besondere Sorgfalt erforderlich. Karten sind in der Lage, Objekte als Schlüssel zu speichern, und sie behalten den Typ bei, aber das führt zu einem Problem beim Gleichheitsvergleich, wenn Sie ein völlig anderes Objekt haben, das alle genau die gleichen Schlüssel und Werte hat.

const m = new Map();
m.set({name: "John"}, 5);
console.log(m.has({name: "John"}));//false

Dieser Code gibt „false“ aus, da die beiden Objekte keine referenzielle Gleichheit haben. Die beiden Objekte sind in Schlüsseln und Werten identisch, aber sie sind nicht genau dasselbe Objekt.

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

Diese Version des Codes gibt „wahr“ aus, da der festgelegte Wert genau dasselbe Objekt ist, das auf Mitgliedschaft getestet wird.

Das Ergebnis des Versuchs, Objekte mit Maps zu zählen, ist in den meisten Fällen, dass alle Objekte eine Zählung von 1 haben, da jedes has() false zurückgibt.

Die Verwendung von Objekten zum Zählen von Objekten hat ein verwandtes, aber etwas anderes Problem. Objektschlüssel werden automatisch in eine Zeichenfolge umgewandelt (außer wenn es sich um Symbole handelt). Wenn Sie versuchen, ein Objekt als Schlüssel eines anderen Objekts zu verwenden, erstellt dieser Typzwang einen Schlüssel gleich „[Objekt Objekt]“.

const obj = {name: "John"}
const count = {};
count[obj] = 5;
console.log(count);// { '[object Object]': 5 }

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 }

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);

The resulting output is:

[
  { employee: { id: 1, name: 'John' }, count: 2 },
  { employee: { id: 2, name: 'Mary' }, count: 3 }
]

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);

The resulting output is:

Map(2) {
  '{"name":"John Doe","age":25}' => 2,
  '{"name":"Mary Jane","age":24}' => 3
}

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.

Das obige ist der detaillierte Inhalt vonDinge zählen in Javascript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn