IlmHamroh
JavaScript Full-stack/10-qism. JavaScript chuqur9/65-dars22 daqiqa
Mundarija (33)

JavaScript metod zanjiri: filter, map, reduce bilan ma'lumot pipeline

Qisqacha: Massiv qaytaradigan metodlarni nuqta bilan ketma-ket ulash mumkin: buyurtmalar.filter(tolanganmi).map(summasi).reduce(qosh, 0). Har bosqich oldingisining natijasini oladi — bu pipeline. Zanjir o'qishga oson, lekin har bosqich butun massivni aylanadi va yangi massiv yasaydi. Odatdagi ro'yxatlarda farq sezilmaydi; million elementda yoki "birinchi topilgani yetarli" holatda oddiy sikl tezroq.

Bu darsda

  • filter, map, toSorted, reduce ni bitta o'qiluvchan zanjirga ulay olasiz va uni to'g'ri formatlaysiz.
  • Zanjir qaysi metodlarda uzilishini bilasiz.
  • Zanjirni bosqichma-bosqich tekshirib, xatoni topa olasiz.
  • Oraliq massivlar narxini va erta chiqish foydasini o'lchab ko'rsata olasiz.
  • vazifalar dagi ma'lumot oqimini o'lchab, hujjatlashtirasiz va modulni yakunlaysiz.

Oldin bilishingiz kerak: filter, reduce, Nusxa bilan o'zgartirish, Guruhlash: Object.groupBy, Pure funksiya va side effect, Ko'p elementni samarali chizish.

1. Nega bu kerak?

Kun oxirida Jasur aka so'raydi: "bugun to'langan buyurtmalardan qancha pul tushdi?" Ma'lumot — buyurtmalar ro'yxati. 08-qism uslubida yozamiz:

js
const buyurtmalar = [
  { stol: 3, summa: 120000, tolandi: true },
  { stol: 1, summa: 45000, tolandi: false },
  { stol: 7, summa: 30000, tolandi: true },
];

let tushum = 0;
for (const b of buyurtmalar) {
  if (b.tolandi) {
    tushum += b.summa;
  }
}
console.log(tushum); // 150000

Ishlaydi. Endi so'nggi to'qqiz darsda o'rganganimiz bilan:

js
const buyurtmalar = [
  { stol: 3, summa: 120000, tolandi: true },
  { stol: 1, summa: 45000, tolandi: false },
  { stol: 7, summa: 30000, tolandi: true },
];

const tushum = buyurtmalar
  .filter((b) => b.tolandi)
  .map((b) => b.summa)
  .reduce((jami, s) => jami + s, 0);

console.log(tushum); // 150000

Uch qator — uch fe'l: tanla, ol, qo'sh. Ularni yuqoridan pastga o'qisangiz, savolning o'zi chiqadi. Bu — metod zanjiri va bugungi darsning mavzusi.

Hayotdan o'xshatish: konveyer. Non zavodida xamir birinchi stansiyada bo'linadi, ikkinchisida shakl oladi, uchinchisida pishadi. Har stansiya faqat oldingisidan kelganini oladi va o'zining bitta ishini qiladi. Bir stansiyani olib tashlash yoki yangisini qo'shish oson. Metod zanjiri ham shunday: har metod — bitta stansiya.

filter darsida birinchi zanjirni ko'rgan edik va "o'qiluvchanlik, tezlik va qachon oddiy sikl yaxshiroq — keyinroq" degan edik. Callback imzosi darsida ham "katta ma'lumotda metodlar zanjirini o'lchaymiz" deb va'da bergan edik. Bugun ikkalasini bajaramiz: avval zanjirni yozish va o'qish qoidalari, keyin uning narxi — haqiqiy o'lchovlar bilan.

2. Zanjir qanday ishlaydi

2.1 Har metod — yangi massiv

Zanjirning siri oddiy: filter massiv qaytaradi, massivda esa map bor. map ham massiv qaytaradi — unda reduce bor. Nuqta oldingi metodning natijasiga murojaat qiladi.

Bosqichlarni alohida o'zgaruvchilarga ajratsak, bu yaqqol ko'rinadi:

js
const buyurtmalar = [
  { stol: 3, summa: 120000, tolandi: true },
  { stol: 1, summa: 45000, tolandi: false },
  { stol: 7, summa: 30000, tolandi: true },
];

const tolanganlar = buyurtmalar.filter((b) => b.tolandi);
const summalar = tolanganlar.map((b) => b.summa);
const tushum = summalar.reduce((jami, s) => jami + s, 0);

console.log(tolanganlar.length, summalar, tushum);
// 2 [ 120000, 30000 ] 150000

Zanjir aynan shu uch qator — faqat oraliq nomlarsiz. Sxemada har bosqichdan keyin nima qolishiga qarang:

flowchart LR
  A["buyurtmalar: 3 ta obyekt"] -- "filter: to'landimi?" --> B["2 ta obyekt"]
  B -- "map: summasini ol" --> C["2 ta son"]
  C -- "reduce: qo'sh" --> D["150000"]

Massiv har bosqichda "torayadi" yoki "shaklini o'zgartiradi": obyektlar → kamroq obyektlar → sonlar → bitta son.

2.2 Pipeline

Ma'lumot pipeline (data pipeline) — ma'lumot ketma-ket bosqichlardan o'tadigan, har bosqich oldingisining natijasini oladigan tuzilma. Inglizcha "pipeline" — "quvur": suv bir uchidan kiradi, yo'lda filtrlardan o'tadi, boshqa uchidan tozalanib chiqadi. Bu so'zni dasturchilar juda ko'p ishlatadi: ma'lumot pipeline, CI pipeline (34-qismda), build pipeline.

Yaxshi pipeline'ning uchta belgisi:

  1. Har bosqich — bitta ish. filter faqat tanlaydi, map faqat aylantiradi.
  2. Bosqichlar toza. Callback'lar tashqi narsani o'zgartirmaydi (Pure funksiya). Shuning uchun bosqichlarni ko'chirish, olib tashlash va alohida sinash xavfsiz.
  3. Kirish o'zgarmaydi. buyurtmalar zanjirdan keyin ham o'sha-o'sha. Har bosqich yangi massiv beradi.

2.3 Nomli bosqichlar

Callback'larga nom bersangiz, zanjir gap kabi o'qiladi:

js
const buyurtmalar = [
  { stol: 3, summa: 120000, tolandi: true },
  { stol: 1, summa: 45000, tolandi: false },
  { stol: 7, summa: 30000, tolandi: true },
];

const tolanganmi = (b) => b.tolandi;
const summasi = (b) => b.summa;
const qosh = (jami, son) => jami + son;

const tushum = buyurtmalar
  .filter(tolanganmi)
  .map(summasi)
  .reduce(qosh, 0);

console.log(tushum); // 150000

"Buyurtmalardan to'langanmi — tanla, summasini — ol, qo'sh". Nomlar kurs qoidasiga mos: predikat — "-mi" bilan (tolanganmi), qiymat qaytaruvchi — natija nomi (summasi). Bonus: qosh va summasi ni boshqa zanjirlarda ham ishlatish mumkin.

Qachon nom berish kerak? Callback bir qarashda tushunarli bo'lsa ((b) => b.summa) — joyida qoldiring. Shart murakkab bo'lsa yoki bir necha joyda takrorlansa — nomli funksiyaga chiqaring.

2.4 Formatlash

«Nomli bosqichlar» dagi zanjir kelishilgan usulda yozilgan — har metod alohida qatorda, nuqta bilan boshlanadi:

js
const tushum = buyurtmalar
  .filter(tolanganmi)
  .map(summasi)
  .reduce(qosh, 0);

Sabablari: bosqichlar ustun bo'lib turadi va ularni sanash oson; bitta bosqichni izohga olish yoki o'chirish — bitta qator; telefonda gorizontal aylantirish yo'q. Prettier ham shunday qiladi: 06-qismda CSS uchun ishlatgan bu vosita JavaScript zanjirini ham shunday formatlaydi (ESLint va Prettier). Ikki-uch qisqa metodli zanjir 70 belgiga sig'sa, uni bitta qatorda qoldirish ham mumkin: [4, 7].map(ikkilan).join(", ").

Tekshirib ko'ring: [4, 7, 10, 3].filter((x) => x > 3).map((x) => x * 2).reduce((a, x) => a + x, 0) nima qaytaradi? Har bosqichdan keyin massiv qanday?

Javob

42. filter dan keyin — [4, 7, 10] (3 o'tmadi). map dan keyin — [8, 14, 20]. reduce — 8 + 14 + 20 = 42. Har bosqich oldingisining natijasini oldi.

3. Zanjir qayerda uziladi

3.1 Massiv qaytarmaydigan metodlar

Zanjir faqat metod massiv qaytarguncha davom etadi. Massiv qaytarmaydigan metod — zanjirning oxiri:

Metod Qaytaradi Keyin zanjir?
filter, map, flatMap, slice, toSorted yangi massiv davom etadi
reduce istalgan qiymat faqat natija massiv bo'lsa
find, at bitta element yo'q
some, every, includes true/false yo'q
join satr satr metodlari
forEach undefined yo'q

Eng ko'p uchraydigan xato — forEach ni zanjir o'rtasiga qo'yish:

js
const narxlar = [35000, 28000, 5000];

narxlar
  .forEach((n) => console.log(n))
  .map((n) => n * 2);
text
TypeError: Cannot read properties of undefined (reading 'map')

Tarjimasi: "undefined ning xususiyatlarini o'qib bo'lmaydi (map ni o'qishda)". forEach undefined qaytardi (Callback imzosi dagi jadval), keyingi nuqta esa undefined.map ni qidirdi. Xabarda forEach haqida bir so'z ham yo'q — u faqat keyingi bosqich nomini aytadi. Qoida: "Cannot read properties of undefined (reading 'X')" ko'rsangiz — X dan oldingi bosqichni tekshiring. Tuzatish: forEach faqat zanjir oxirida bo'lishi mumkin.

Mutatsiya qiluvchi metodlar ham tuzoq qo'yadi. push massiv emas, yangi uzunlikni qaytaradi — keyingi .filter son ustida chaqiriladi va ... .filter is not a function xatosi chiqadi.

3.2 sort zanjirda

sort massiv qaytaradi, shuning uchun zanjir uzilmaydi. Lekin u o'sha massivni qaytaradi va uni o'zgartiradi (sort):

js
const menyu = [
  { nom: "Osh", narx: 35000 },
  { nom: "Choy", narx: 5000 },
];

const nomlar = menyu
  .sort((a, b) => a.narx - b.narx)
  .map((t) => t.nom);

console.log(nomlar); // [ 'Choy', 'Osh' ]
console.log(menyu[0].nom); // Choy

Faqat nomlar ro'yxatini olmoqchi edik, lekin menyu ning tartibi ham buzildi. Zanjir boshidagi sort — kirish ma'lumotini o'zgartiradi va pipeline'ning uchinchi belgisini buzadi. Tuzatish: toSorted (Nusxa bilan o'zgartirish). Zanjir o'rtasidagi sort (filter dan keyin) xavfsiz — u oraliq massivni o'zgartiradi. Lekin toSorted har joyda xavfsiz va o'qigan odamni o'ylatmaydi.

Tekshirib ko'ring: Quyidagi zanjirda xato bormi? buyurtmalar.filter((b) => b.tolandi).find((b) => b.summa > 100000).map((b) => b.stol)

Javob

Bor. find massiv emas, bitta obyekt (yoki undefined) qaytaradi — obyektda map yo'q. Topilsa — ... .map is not a function, topilmasa — Cannot read properties of undefined (reading 'map'). Bitta stol kerak bo'lsa — .find(...)?.stol. Hammasi kerak bo'lsa — find o'rniga filter.

4. Zanjirni tekshirish

Zanjir noto'g'ri natija bersa, qaysi bosqichda buzilganini qanday topasiz? Uchta usul bor.

1. Bosqichlarni o'zgaruvchilarga ajrating. «Har metod — yangi massiv» bo'limidagidek. Har o'zgaruvchini chiqarib ko'ring. Zanjir ichidagi xato darhol bitta qatorga tushadi.

2. console.table bilan ko'ring. Obyektlar massivini jadval qilib chiqaradi (console API):

js
const tolanganlar = buyurtmalar.filter(tolanganmi);
console.table(tolanganlar);

Jadvalda tolandi ustuniga qarab, filtr to'g'ri ishlaganini bir qarashda ko'rasiz.

3. Callback ichida to'xtash nuqtasi. DevTools'da callback qatoriga breakpoint qo'ying (DevTools bilan debug qilish). Har element uchun to'xtaydi va uning qiymatini ko'rsatadi. Nomli callback'larga (tolanganmi) to'xtash nuqtasini qo'yish ayniqsa oson.

Muammo topilgach, o'zgaruvchilarni qoldirish ham, zanjirni qayta yig'ish ham mumkin. Uch-to'rt bosqichli zanjir — o'qishga qulay. Yetti-sakkiz bosqichli zanjir — ehtimol bir necha nomli qismga bo'linishi kerak.

5. Zanjirning narxi

5.1 Har bosqich — to'liq o'tish va yangi massiv

Zanjirning qulayligi bepul emas. filter → map → reduce uchun kompyuter:

  1. Butun massivni bir marta aylanadi (filter) va yangi massiv yasaydi.
  2. O'sha yangi massivni yana aylanadi (map) va yana bir massiv yasaydi.
  3. Uni uchinchi marta aylanadi (reduce).

Boshida g'alati tuyulishi mumkin: elementlar konveyerdagi non kabi birma-bir o'tmaydimi? Yo'q. Har stansiya butun partiyani tugatadi, keyingisi shundan keyin boshlaydi. Callback'lar ichiga console.log qo'yib, buni o'z ko'zingiz bilan ko'ring:

Konsolda avval uchala filter, keyin ikkala map yozuvi chiqadi — aralash emas. Bu tartibni «Erta chiqish» bo'limida yana eslaymiz: aynan shu sabab zanjir "uchtasi topildi, yetadi" deb to'xtay olmaydi.

Oddiy sikl esa bitta o'tishda, oraliq massivlarsiz ishlaydi. Farq qanchalik katta? Taxmin qilmaymiz — o'lchaymiz.

5.2 O'lchov: million buyurtma

Million buyurtmali sinov massivini Array.from bilan yasaymiz va to'langanlar summasini uch usulda hisoblaymiz. Har usul to'qqiz marta o'lchandi, grafikda — o'rtadagi (mediana) natija:

1 000 000 buyurtma: to'langanlar summasi
  • filter → map → reduce3 o'tish, 2 oraliq massiv31,6 ms
  • bitta reduce1 o'tish9,4 ms
  • for...of1 o'tish11,2 ms

Manba: O'lchov: Node 24.21, Windows 11, performance.now, 9 o'lchovning medianasi, 2026-10-04

Zanjir taxminan uch barobar sekinroq. Lekin raqamlarga diqqat bilan qarang: 31 millisekund — million buyurtma uchun. Xuddi shu o'lchov 1 000 buyurtmada: zanjir 0,03 ms, sikl 0,03 ms. Ko'z ham, foydalanuvchi ham farqni sezmaydi.

O'lchov kodi — sizning kompyuteringizda raqamlar boshqacha chiqadi, lekin nisbat o'xshash bo'ladi:

js
const buyurtmalar = Array.from({ length: 1_000_000 }, (_, i) => ({
  summa: ((i * 7919) % 100000) + 1000,
  tolandi: i % 4 !== 0,
}));

const boshi = performance.now();
const tushum = buyurtmalar
  .filter((b) => b.tolandi)
  .map((b) => b.summa)
  .reduce((jami, s) => jami + s, 0);
console.log(tushum, `${(performance.now() - boshi).toFixed(1)} ms`);

1_000_000 — pastki chiziq faqat o'qish uchun, son o'sha million (Son yozish shakllari). performance.now — Ko'p elementni samarali chizish darsidagi sekundomer, Node'da ham bor.

5.3 Bosqichlar tartibi

Narxni kamaytirishning eng arzon usuli — tartib. filter darsidagi qoida: avval keraksizini olib tashlang, keyin qolganini ishlang. Million buyurtmaga QQS maydoni qo'shib (map da { ...b, qqs }), to'langanlarini tanlaymiz. Natija bir xil — 750 000 ta buyurtma — lekin vaqt har xil:

Tartib map necha marta ishladi Vaqt (mediana)
map → filter 1 000 000 131,5 ms
filter → map 750 000 84,8 ms

map yangi obyekt yasaydi — bu qimmat ish. Avval filter qilinganda, chorak buyurtma uchun obyekt umuman yasalmadi. Kodni o'zgartirish — ikki qatorni almashtirish. Raqamlar o'sha o'lchovdan: Node 24.21, mediana.

Tekshirib ko'ring: Mijozlar ro'yxatidan faqat Toshkentdagilarning ismlarini katta harf bilan olish kerak. Qaysi tartib yaxshiroq: .map(ismniKattala).filter(toshkentlikmi) yoki .filter(toshkentlikmi).map(ismniKattala)? Birinchisi ishlaydimi umuman?

Javob

Ikkinchisi. Birinchisi ishlamasligi ham mumkin: map dan keyin elementlar ism satrlari — ularda shahar maydoni yo'q, toshkentlikmi hech narsani topa olmaydi. Avval filter — kerakli maydonlar hali joyida va keraksizlar map gacha olib tashlanadi.

6. Erta chiqish

6.1 Zanjir to'xtamaydi

Bir holatda farq "uch barobar" emas, ming barobar bo'ladi. Jasur aka so'raydi: "100 000 so'mdan katta birinchi uchta buyurtma qaysi?" Zanjir bilan:

js
const birinchiUchta = buyurtmalar
  .filter((b) => b.summa > 100000)
  .slice(0, 3);

filter "birinchi uchta" haqida hech narsa bilmaydi. U million buyurtmaning hammasini tekshiradi, keyin slice faqat uchtasini oladi. Qolgan ish — behuda.

Sikl esa uchta topilishi bilan to'xtay oladi (break):

js
const birinchiUchta = [];
for (const b of buyurtmalar) {
  if (b.summa > 100000) {
    birinchiUchta.push(b);
    if (birinchiUchta.length === 3) {
      break;
    }
  }
}

Xuddi o'sha million buyurtmada: zanjir — 7,1 ms, sikl — 0,01 ms. Kerakli uchtasi ro'yxat boshida edi — sikl bir necha yuz elementni ko'rib, ishini tugatdi. Erta chiqish (early exit) — natija tayyor bo'lishi bilan qolgan ishni to'xtatish. return va erta qaytish darsidagi g'oyaning sikldagi shakli.

6.2 Erta chiqadigan metodlar

Bitta element yoki ha/yo'q javob kerak bo'lsa, erta chiqadigan metodlar allaqachon bor:

Savol Erta chiqmaydi Erta chiqadi
"Birinchi mos qaysi?" filter(...)[0] find
"Mos bormi?" filter(...).length > 0 some
"Hammasi mosmi?" filter(...).length === n every

filter darsida find va some chaqiruvlarini sanagan edik — ular birinchi javobda to'xtagan edi. "Birinchi N ta" uchun esa tayyor massiv metodi yo'q — sikl va break.

2025-yilda JavaScript'ga "dangasa" zanjir ham qo'shildi — iterator helpers: buyurtmalar.values().filter(...).take(3).toArray(). U elementlarni birma-bir, kerak bo'lgandagina ishlaydi va uchtasi topilishi bilan to'xtaydi. Uni Iterator helpers darsida o'rganamiz — hozir bilish shart emas.

7. Qachon zanjir, qachon sikl

Vaziyat Tanlov
Odatdagi ro'yxat (yuzlab, minglab element) zanjir — o'qiluvchanlik muhimroq
Bitta element yoki ha/yo'q kerak find, some, every
"Birinchi N ta", natija topilishi bilan to'xtash for...of + break
Bir o'tishda bir nechta natija (yig'indi va soni va eng kattasi) for...of yoki bitta reduce
Juda katta ma'lumot (yuz minglab) va o'lchov sekinlikni ko'rsatdi bitta o'tishli sikl

Asosiy qoida: avval o'qiluvchan yozing, keyin o'lchang, keyin — kerak bo'lsa — tezlashtiring. "Sikl tezroq" deb har zanjirni siklga aylantirish — o'qiluvchanlikni hech kim sezmaydigan millisekundga almashtirish. Sekinlik bo'lsa, u ko'pincha zanjirda emas, boshqa joyda — buni bugungi «Vazifalar qadami» da ko'rasiz.

8. Ko'p uchraydigan xatolar

8.1 forEach zanjir o'rtasida

«Massiv qaytarmaydigan metodlar» bo'limi: TypeError: Cannot read properties of undefined (reading 'map'). Tuzatish: forEach ni oxirga qo'ying yoki map ishlating.

8.2 Zanjir boshida sort

«sort zanjirda» bo'limi: kirish massivi o'zgaradi, xato xabari yo'q. Tuzatish: toSorted.

8.3 map dan keyin kerakli maydon yo'qoladi

buyurtmalar.map((b) => b.summa).filter((b) => b.tolandi) — summa sonlarida tolandi yo'q, filter bo'sh massiv qaytaradi. Xato xabari yo'q, natija — []. Tuzatish: avval filter, keyin map.

8.4 Zanjir o'rtasidagi reduce boshlang'ich qiymatsiz

Bo'sh massiv filter dan keyin juda tez paydo bo'ladi: bugun hech kim to'lamagan bo'lsa, filter [] qaytaradi. Keyingi reduce((a, s) => a + s) — TypeError: Reduce of empty array with no initial value (reduce). Tuzatish: zanjirdagi reduce ga doim boshlang'ich qiymat.

8.5 Juda uzun zanjir

O'n bosqichli, har birida uch qatorli callback'li zanjirni hech kim bir qarashda o'qiy olmaydi. Tuzatish: callback'larni nomli funksiyalarga chiqaring, zanjirni ma'noli bo'laklarga bo'lib, oraliq natijalarga nom bering.

9. Mashqlar

1-mashq (oson): O'tganlar ro'yxati

Imtihondan o'tganlarning (ball ≥ 60) ismlarini o'zbek alifbosi tartibida, vergul bilan chiqaring. Bitta zanjir: filter → map → toSorted → join.

js
const talabalar = [
  { ism: "Shuhrat", ball: 78 },
  { ism: "Olim", ball: 54 },
  { ism: "O'tkir", ball: 91 },
  { ism: "Aziz", ball: 60 },
];
Yechim
js
const talabalar = [
  { ism: "Shuhrat", ball: 78 },
  { ism: "Olim", ball: 54 },
  { ism: "O'tkir", ball: 91 },
  { ism: "Aziz", ball: 60 },
];

const otganlar = talabalar
  .filter((t) => t.ball >= 60)
  .map((t) => t.ism)
  .toSorted((a, b) => a.localeCompare(b, "uz"))
  .join(", ");

console.log(otganlar); // Aziz, O'tkir, Shuhrat

To'rt bosqich: tanla, ismini ol, sarala, ula. join satr qaytaradi — zanjirning oxiri. localeCompare(…, "uz") — "O'tkir" z dan keyingi o' harfi bilan, shuning uchun "Shuhrat" dan oldin, lekin "Aziz" dan keyin (sort).

2-mashq (o'rta): Taksi: qimmat safarlarning o'rtachasi

30 000 so'mdan qimmat safarlarning o'rtacha narxini toping. Bunday safar bo'lmasa — 0 chiqsin, NaN emas.

Ishora: zanjir bilan narxlarni oling, o'rtacha uchun yig'indini uzunlikka bo'ling — bo'sh massivni alohida tekshiring.

js
const safarlar = [
  { narx: 25000 },
  { narx: 38000 },
  { narx: 52000 },
  { narx: 18000 },
];
Yechim
js
function qimmatlarOrtachasi(safarlar) {
  const narxlar = safarlar
    .map((s) => s.narx)
    .filter((narx) => narx > 30000);
  if (narxlar.length === 0) {
    return 0;
  }
  return narxlar.reduce((jami, n) => jami + n, 0) / narxlar.length;
}

const safarlar = [
  { narx: 25000 },
  { narx: 38000 },
  { narx: 52000 },
  { narx: 18000 },
];

console.log(qimmatlarOrtachasi(safarlar)); // 45000
console.log(qimmatlarOrtachasi([])); // 0

Bu yerda map filter dan oldin — va bu to'g'ri: filtr narxning o'ziga qaraydi, obyektning boshqa maydoni kerak emas. Bosqichlar tartibi qoidasi "qimmat ishni keyinga qoldir" degani; bu map esa arzon — maydonni olish xolos. Zanjir o'rtacha uchun ikki marta kerak bo'lgan massivda to'xtadi — shuning uchun oraliq nom (narxlar) bor. Bo'sh massivda 0 / 0 — NaN bo'lardi, erta return 0 buni oldini oldi.

3-mashq (qiyin): Kunlik hisobot — eng ko'p tushum bergan ikki taom

Buyurtmalardan har taomning jami tushumini hisoblang va eng ko'p tushum bergan ikkita taomni osh — 105000 so'm ko'rinishida chiqaring. Pipeline bosqichlari:

  1. Object.groupBy — taom bo'yicha (Guruhlash).
  2. Object.entries → map — har taom uchun { taom, tushum }.
  3. toSorted — tushum kamayishi bo'yicha.
  4. slice(0, 2) → map — satrga.
js
const buyurtmalar = [
  { taom: "osh", summa: 35000 },
  { taom: "choy", summa: 5000 },
  { taom: "osh", summa: 70000 },
  { taom: "manti", summa: 60000 },
  { taom: "choy", summa: 10000 },
];
Yechim
js
const buyurtmalar = [
  { taom: "osh", summa: 35000 },
  { taom: "choy", summa: 5000 },
  { taom: "osh", summa: 70000 },
  { taom: "manti", summa: 60000 },
  { taom: "choy", summa: 10000 },
];

const qosh = (jami, b) => jami + b.summa;

const taomlar = Object.groupBy(buyurtmalar, (b) => b.taom);

const hisobot = Object.entries(taomlar)
  .map(([taom, royxat]) => ({ taom, tushum: royxat.reduce(qosh, 0) }))
  .toSorted((a, b) => b.tushum - a.tushum)
  .slice(0, 2)
  .map((q) => `${q.taom} — ${q.tushum} so'm`);

console.log(hisobot.join("\n"));

Konsolda:

text
osh — 105000 so'm
manti — 60000 so'm

Besh bosqichli pipeline: guruhla, yig', sarala, kes, yoz. Har bosqich bitta ish qiladi, kirish massivi o'zgarmadi. \n — yangi qator (Template literals). toSorted o'rnida sort ham xavfsiz edi — u map yasagan oraliq massivni tartiblardi. Lekin toSorted bu haqda o'ylashni talab qilmaydi.

4-mashq: Vazifalar qadami — oqimni o'lchash va hujjatlashtirish

So'nggi besh darsda vazifalar da ma'lumot oqimi shakllandi: holat → filter → toSorted → map(qatorYasa) → ekran, yonida esa groupBy → hisob. Bu — pipeline. Uni katta ma'lumotda o'lchaymiz va README'da hujjatlashtiramiz.

  1. Yangi branch: git switch -c chore/malumot-oqimi.
  2. Brauzerda vazifalar ni oching. flat, fill va Array.from darsidagi kurs/mashqlar/10/07-sinov/sinov-vazifalar.js dan foydalanib, konsolda 10 000 ta vazifa yasang.
  3. korinadiganlar, statistika va render vaqtini alohida o'lchang. Qaysi biri sekin?
  4. Natijaga qarab qaror qiling: zanjirni siklga aylantirish kerakmi?
  5. README'ga "Ma'lumot oqimi" bo'limini yozing.
Yechim

Konsolga (sinov-vazifalar.js dagi kod, faqat length — 10 000):

js
holat.vazifalar = Array.from({ length: 10000 }, (_, i) => ({
  id: i + 1,
  matn: `Sinov vazifasi ${i + 1}`,
  bajarildi: i % 3 === 0,
}));
holat.keyingiId = 10001;

function olch(nom, ish) {
  const boshi = performance.now();
  ish();
  console.log(`${nom}: ${(performance.now() - boshi).toFixed(1)} ms`);
}

olch("korinadiganlar", korinadiganlar);
olch("statistika", statistika);
olch("render", render);

Biz Chrome 154 da olgan natija (sizda raqamlar boshqacha bo'ladi):

text
korinadiganlar: 2.1 ms
statistika: 1.7 ms
render: 104.3 ms

Bu o'lchov darsning eng muhim xulosasini ko'rsatadi:

  • Zanjir sekin emas. filter + toSorted 10 000 vazifada — 2 millisekund. groupBy — undan ham kam.
  • Sekin joy — DOM. render vaqtining 95 foizdan ko'pi qatorYasa 10 000 ta li, katak, yorliq va tugma yasashiga va brauzer ularni joylashtirishiga ketdi. render ichidagi zanjir esa o'sha 2 ms.
  • Qaror. Zanjirni siklga aylantirish 2 ms dan 1 ms ga tushirardi — 104 ms ning yonida bu hech narsa. O'qiluvchan kod qoladi. Haqiqatan 10 000 vazifa kerak bo'lsa, yechim boshqa: faqat ekranda ko'rinadigan qatorlarni chizish — Uzun ro'yxatlar: virtualizatsiya darsida ko'ramiz. Oddiy foydalanuvchida esa o'nlab vazifa bo'ladi.

Ko'p elementni samarali chizish darsidagi qoida tasdiqlandi: taxmin emas, o'lchov. Agar "sikl tezroq" degan gapga ishonib zanjirni buzganimizda, ilova sezilarli tezlashmasdi.

README'ga qo'shing:

markdown
## Ma'lumot oqimi

Holat (`holat`) — yagona haqiqat manbai. Ekran har safar undan
qayta hisoblanadi, `holat.vazifalar` ning o'zi tartiblanmaydi:

- ro'yxat: `filter(mosmi)` → `toSorted(faollarOldin)` →
  `map(qatorYasa)` → `replaceChildren`
- hisob: `Object.groupBy(guruhNomi)` → "N ta vazifa qoldi,
  M ta bajarildi"

O'lchov (Chrome, 10 000 vazifa): zanjirlar ~2 ms, DOM — ~100 ms.

Commit, merge va push — HOF modulining (10-qism, 1–9-darslar) yakuni:

bash
git add README.md
git commit -m "Docs: ma'lumot oqimi va o'lchov natijasi"
git switch main
git merge chore/malumot-oqimi
git branch -d chore/malumot-oqimi
git push

Sahifani yangilang — sinov vazifalari yo'qoladi, ilova boshlang'ich uch vazifaga qaytadi. Kodda o'zgarish yo'q: bu qadam faqat o'lchov va hujjat.

To'qqiz darsda vazifalar.js da nima o'zgardi:

Dars O'zgarish Turi
Callback imzosi filtr tugmalari — forEach refaktoring
map qatorYasa + map refaktoring
filter korinadiganlar — filter refaktoring
reduce faollarSoni — reduce refaktoring
sort bajarilmaganlar tepada yangi imkoniyat
Nusxa bilan o'zgartirish toSorted, toSpliced refaktoring
Array.from 500 ta sinov vazifasi (konsolda) sinov
Guruhlash statistika() (faollarSoni o'rniga): hisobda bajarilganlar soni ham yangi imkoniyat
shu dars ma'lumot oqimi o'lchandi va hujjatlandi hujjat

10. Real ishda

  • Ma'lumotni tayyorlash. Serverdan kelgan ro'yxatni ekranga tayyorlash — deyarli har doim zanjir: keraksizini olib tashla, sarala, kerakli ko'rinishga aylantir. React komponentlarida vazifalar.filter(...).map((v) => <li>…</li>) — har kuni yoziladigan qator (17-qism).
  • Hisobotlar va tahlil. "Bu oy, to'langan, Toshkentdagi buyurtmalarning o'rtacha summasi" — filter → filter → map → reduce. Data Science'dagi jadval kutubxonalari (masalan Python'dagi pandas) ham aynan shunday zanjir uslubida ishlaydi.
  • Performans. Tajribali dasturchi "sikl tezroq" deb darhol qayta yozmaydi — avval profil qiladi. Bugungi «Vazifalar qadami» dagi natija — sekinlik zanjirda emas, DOM'da — real loyihalarda juda ko'p uchraydi.
  • Kod ko'rib chiqish. Uzun, nomsiz callback'li zanjir va sort bilan boshlanadigan zanjir — tez-tez qaytariladigan kod. Nomli bosqichlar va toSorted — "toza kod" belgisi.
  • Intervyu. "Bu zanjir necha marta aylanadi?", "nega filter → map, teskarisi emas?", "filter(...)[0] o'rniga nima yozasiz?" — javoblar: har bosqich bir marta; keraksizini avval olib tashlash; find.

Xulosa

  • Massiv qaytaradigan metodlar zanjirga ulanadi: har bosqich oldingisining natijasini oladi — bu pipeline.
  • Har metod alohida qatorda, nuqta bilan; murakkab callback — nomli funksiya (tolanganmi, summasi).
  • Zanjir forEach, find, some, join va boshlang'ich qiymatli reduce da tugaydi. "Cannot read properties of undefined (reading 'X')" — X dan oldingi bosqichni tekshiring.
  • Zanjir boshida sort emas, toSorted. Avval filter, keyin map.
  • Har bosqich — to'liq o'tish va yangi massiv: millionda ~3 barobar sekinroq, mingda — farq yo'q.
  • Birinchi topilgani yetarli bo'lsa — find/some yoki for...of + break. Avval o'qiluvchan yozing, keyin o'lchang.

Keyingi dars: Massivga o'xshash obyektlar va teshikli massivlar — NodeList va { length: n } kabi "massivga o'xshash" narsalar, teshiklar va ular metodlarda qanday kutilmagan xulq ko'rsatishi.

Manbalar

  • MDN: "Array" — "Iterative methods", "Array.prototype.find()", "Iterator.prototype.take()" — developer.mozilla.org
  • MDN: "Performance: now() method" — developer.mozilla.org
  • O'lchovlar: Node 24.21 va Chrome 154, Windows 11, 2026-10-04 (kurs muallifi kompyuteri)
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript metod zanjiri: filter, map, reduce bilan ma'lumot pipeline — IlmHamroh