Rumah  >  Artikel  >  hujung hadapan web  >  Mengira perkara dalam Javascript

Mengira perkara dalam Javascript

WBOY
WBOYasal
2024-08-08 07:17:32666semak imbas

Counting things in Javascript

Jika anda ingin mengira bilangan item varieti tertentu dalam tatasusunan, anda boleh menapis tatasusunan itu dan menyemak panjang hasilnya.

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

Ini mempunyai kerumitan masa O(n), yang merupakan teori ideal untuk jenis masalah ini. Ia menggunakan beberapa memori tambahan untuk memegang tatasusunan kedua, tetapi untuk mengira hanya satu jenis item, ini adalah pendekatan biasa dan cukup cekap dalam kebanyakan situasi. Walau bagaimanapun, ini bukan pendekatan yang cekap jika anda mahukan pengiraan setiap pelbagai item dalam tatasusunan.

Masalah dengan penapis

Jika kita mahu mengira bukan sahaja 'c' tetapi setiap huruf dalam tatasusunan, aplikasi naif teknik ini akan menjadi seperti ini:

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

Ini menghasilkan output berikut:

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

Pengiraan adalah betul, tetapi terdapat lebihan, yang boleh diperbaiki dengan menggunakan Set terlebih dahulu.

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

Output yang terhasil tidak mempunyai pendua:

a 1
b 2
c 3

Walau bagaimanapun, ia mempunyai kerumitan masa O(n^2), kerana setiap penapis melelang melalui keseluruhan tatasusunan, dan ia mesti melakukannya untuk setiap huruf unik.

Pendekatan yang lebih cekap

Anda boleh melakukan kiraan ini dengan kerumitan masa O(n). Prinsip umum adalah untuk mengulang tatasusunan sekali sahaja. Untuk setiap item yang ditemui, semak sama ada anda sudah mempunyai kiraan untuk item itu. Jika anda berbuat demikian, tambahkannya sebanyak 1. Jika tidak, tambahkan kiraan untuk item itu dengan nilai yang ditetapkan kepada 1.

Javascript mempunyai dua mekanisme berbeza yang sesuai untuk menyimpan kiraan. Kita boleh menggunakan objek atau Peta. Ambil perhatian bahawa ini adalah rujukan kepada struktur data Peta dan bukan kaedah tatasusunan map(). Menggunakan Peta adalah lebih cekap, tetapi menggunakan objek untuk ini masih agak biasa, jadi kita akan melihat cara mengira dengan kedua-duanya.

Mengira dengan Peta

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() menyemak sama ada nilai sudah ada dalam Peta. Set() menyimpan nilai dalam Peta, sama ada mencipta nilai baharu atau menimpa nilai sedia ada. Get() memperoleh nilai semasa. Ambil perhatian bahawa has(), set(), dan get() ialah kerumitan masa O(1), kerana cincang digunakan secara dalaman.

Jika kami ingin mengeluarkan kiraan huruf tertentu kemudian, kami boleh melakukan sesuatu seperti:

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

Membilang dengan objek

Walaupun mengira dengan objek adalah lebih perlahan, perbezaan dalam prestasi mungkin tidak ketara jika anda tidak mengira kuantiti item yang banyak. Objek juga mempunyai lebih banyak sokongan pelayar daripada Peta, walaupun perbezaan itu menjadi hampir tidak penting pada ketika ini. Menurut caniuse.com, Map disokong dalam 96.28% pelayar pada masa penulisan ini. Objek adalah bahagian penting dalam bahasa Javascript dan harus mempunyai 100% sokongan penyemak imbas, tetapi caniuse.com tidak mempunyai penyenaraian untuknya. Sebab utama untuk mempelajari cara menggunakan objek untuk kiraan adalah kerana terdapat banyak kod lama yang menggunakan teknik ini. Sesetengah orang yang belajar daripada kod lama juga menulis kod baharu menggunakan pendekatan ini.

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 }

Kod ini mengikut struktur yang sama seperti kod menggunakan Peta. Perbezaannya adalah dalam sintaks untuk Peta dan objek. Kata kunci "dalam" digunakan untuk menguji sama ada objek mempunyai kunci dengan nama itu. Sintaks kurungan digunakan untuk mendapatkan dan menetapkan nilai. Ambil perhatian bahawa ujian untuk keahlian, tetapan dan mendapatkan nilai daripada objek ialah operasi kerumitan masa O(1), kerana objek secara dalaman menggunakan cincang untuk kekunci.

Masalah mengira objek

Jika perkara yang anda kira adalah objek, penjagaan tambahan diperlukan. Peta mampu menyimpan objek sebagai kunci dan ia mengekalkan jenisnya, tetapi itu menimbulkan masalah untuk perbandingan kesamaan jika anda mempunyai objek yang sama sekali berbeza yang mempunyai semua kunci dan nilai yang sama.

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

Kod ini mengeluarkan "false", kerana kedua-dua objek tidak mempunyai kesamaan rujukan. Kedua-dua objek adalah sama dalam kekunci dan nilai, tetapi ia bukan objek yang sama.

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

Versi kod ini mengeluarkan "true", kerana set nilai adalah objek yang sama yang sedang diuji untuk keahlian.

Hasil percubaan mengira objek dengan Peta dalam kebanyakan kes ialah semua objek akan berakhir dengan kiraan 1, kerana setiap has() mengembalikan palsu.

Menggunakan objek untuk mengira objek mempunyai masalah yang berkaitan tetapi berbeza sedikit. Kekunci objek secara automatik dipaksa kepada rentetan (Kecuali apabila ia adalah simbol). Jika anda cuba menggunakan objek sebagai kunci objek lain, paksaan jenis itu mencipta kunci yang sama dengan "[objek Objek]".

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.

Atas ialah kandungan terperinci Mengira perkara dalam Javascript. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn