Topik temu duga representatif

Temu duga umum: Bagaimanakah Iterator.concat menggubah sumber data secara lazy?

UmumSukar
Pasukan Editorial Offer.ccDiterbitkan Dikemas kini

Soalan

Laksanakan lelaran lazy yang menggabungkan tatasusunan, Set, dan penjana, kemudian terangkan sempadan antara Iterator.concat, Array.concat, Iterator.from, dan flatMap.

1. Soalan dan skop

Sebuah agregator log membaca tatasusunan dalam ingatan, Set yang telah dinyahduplikasi, dan penjana berhalaman mengikut urutan keutamaan; pengguna hanya memerlukan 100 rekod pertama. Gunakan Iterator.concat sambil mengekalkan sifat kelazian (laziness), dan terangkan input tidak terhingga, pengecualian, serta pembersihan apabila penggunaan berhenti lebih awal.

2. Perkara yang diuji oleh penemu duga

  • Membezakan Iterable daripada Iterator dan mengetahui bahawa Iterator.concat memerlukan argumen Iterable.
  • Menerangkan bahawa hasilnya ialah Iterator lazy baharu yang menarik input secara berurutan hanya apabila digunakan.
  • Mengenal pasti bahawa sumber tidak terhingga menyembunyikan setiap sumber yang berikutnya dan senarai argumen mesti kekal terhingga.
  • Mengendalikan pembersihan return, kes TypeError, sandaran keserasian, dan pematerian tatasusunan yang tidak perlu.

3. Soalan untuk dijelaskan terlebih dahulu

  1. Adakah setiap input merupakan Iterable yang boleh diulang atau Iterator sekali guna yang telah pun dimajukan?
  2. Adakah pengguna memerlukan antara muka penstriman atau tatasusunan pada sempadan?
  3. Adakah mana-mana input memiliki kursor fail, rangkaian, atau pangkalan data yang mesti ditutup apabila berhenti awal?
  4. Adakah pelayar sasaran dan Node menyediakan Iterator.concat natif, atau adakah polyfill dibenarkan?

4. Jawapan tiga puluh saat

Saya akan mengesahkan bahawa setiap argumen melaksanakan Symbol.iterator, kemudian mencipta Iterator lazy dengan Iterator.concat. Ia memperoleh setiap input mengikut urutan dan membaca nilai hanya apabila pengguna memanggil next, take, atau menyebarkan (spread) hasilnya. take(100) berhenti menarik nilai dan memberi peluang kepada lelaran pendasar untuk ditutup. Letakkan input tidak terhingga di bahagian akhir atau hadkan penggunaan; pada persekitaran masa jalan yang lebih lama, gunakan sandaran penjana dengan semantik kelazian dan pembersihan yang sama.

5. Perbincangan mendalam langkah demi langkah

Langkah 1: Tetapkan sempadan Iterable

Iterator.concat menerima Iterable, bukan sekadar objek dengan next. Tatasusunan, Set, dan objek penjana layak digunakan. Iterator kosong harus dibalut terlebih dahulu dengan Iterator.from; ini memberikan cara yang jelas kepada concat untuk memperoleh dan menutup setiap iterator input.

Langkah 2: Bina gubahan lazy

js
function* pages() {
  yield { source: "page", id: 1 };
  yield { source: "page", id: 2 };
}

const memory = [{ source: "memory", id: 1 }];
const unique = new Set([{ source: "set", id: 1 }, { source: "set", id: 2 }]);
const merged = Iterator.concat(memory, unique, pages());
const firstThree = merged.take(3).toArray();

Mencipta merged tidak melintasi sebarang input; toArray memulakan penggunaan. Nilai dikeluarkan mengikut urutan ingatan, Set, dan halaman, dan concat tidak menyahduplikasi atau mengubahnya.

Langkah 3: Fahami keadaan penggunaan

Iterator yang dikembalikan menyimpan input dan kedudukan semasa. Selepas seorang pengguna memajukannya, pengguna lain hanya melihat baki yang tinggal. Memainkan semula memerlukan Iterator baharu daripada Iterable sumber. Jika hanya N nilai pertama diperlukan, gunakan take selepas concat dan bukannya menyebarkannya terlebih dahulu.

Langkah 4: Hadkan input tidak terhingga

Mana-mana input mungkin tidak terhingga, menjadikan hasilnya tidak terhingga. Jika input pertama tidak pernah berakhir, input berikutnya tidak dapat dicapai; letakkan kelompok terhingga terlebih dahulu atau kuat kuasakan take, had masa (timeout), dan pembatalan pada sempadan pengguna. Jangan tulis Iterator.concat(...infiniteIterables()), kerana menyebarkan senarai argumen tidak akan pernah selesai.

Langkah 5: Pembersihan, ralat, dan sandaran

Apabila penggunaan berhenti atau melontarkan ralat, iterator semasa harus mendapat peluang untuk menjalankan return, melepaskan kursor, pemegang fail, atau sambungan. Iterator tersuai boleh merekodkan pembersihan dalam finally. Pada persekitaran masa jalan tanpa sokongan natif, sebuah penjana boleh melakukan yield* pada input mengikut urutan dan menyebarkan return; sandaran tersebut tidak boleh menyalin setiap input ke dalam tatasusunan secara senyap-senyap.

6. Contoh jawapan berkualiti tinggi

Saya akan mengesahkan input Iterable, mencipta gubahan lazy dengan Iterator.concat, dan memanggil take(100) atau toArray hanya pada sempadan pengguna. concat memperoleh input mengikut urutan dan tidak menyahduplikasi nilainya. Input pertama yang tidak terhingga menjadikan sumber seterusnya tidak dapat dicapai, jadi saya akan mengehadkan penggunaan dan menguji pembersihan henti awal melalui return. Untuk persekitaran masa jalan yang lebih lama, sandaran penjana boleh mengekalkan kelazian, susunan, keadaan sekali guna, dan pembersihan tanpa memateri sumber-sumber tersebut.

7. Kesilapan lazim

  • Menghantar objek dengan hanya next → TypeError → balutkannya dengan Iterator.from atau laksanakan Symbol.iterator.
  • Menganggap concat dilaksanakan serta-merta → I/O tersembunyi → ingat bahawa penggunaan menarik nilai.
  • Meletakkan Iterable tidak terhingga di tempat pertama → sumber seterusnya tidak pernah dicapai → susun semula dan hadkan penggunaan.
  • Menyebarkan segalanya terlebih dahulu → lonjakan memori dan kependaman → panggil toArray hanya pada sempadan tatasusunan yang jelas.
  • Mengabaikan return henti awal → kebocoran kursor → uji Iterable yang mengira dan sahkan pembersihan.

8. Soalan susulan

Susulan 1: Bagaimanakah ia berbeza daripada Array.concat?

concat tatasusunan memproses tatasusunan yang dimateri serta-merta dan mengembalikan tatasusunan. Iterator.concat menerima Iterable dan mengembalikan Iterator lazy yang boleh mewakili penjana dan sumber tidak terhingga.

Susulan 2: Mengapakah tidak menghantar setiap Iterator secara terus?

Iterator kosong yang bukan Iterable membiarkan pemilikan dan penutupan input yang belum dicapai menjadi tidak jelas. Balutkannya dengan Iterator.from untuk menetapkan sempadan Iterable.

Susulan 3: Bilakah flatMap lebih sesuai digunakan?

Apabila input itu sendiri merupakan jujukan Iterable yang besar atau tidak terbatas, flatMap boleh menghasilkan dan meratakannya secara berperingkat. concat lebih jelas untuk set input yang terhingga dan diketahui.

Susulan 4: Bagaimanakah anda mengesahkan pembersihan?

Gunakan Iterable ujian yang melaksanakan next dan return, rekodkan tarikan dan penutupan, serta sahkan bahawa take, gangguan pengguna, dan ralat panggil balik menghentikan penarikan dan memanggil return.

Sumber awam

Soalan berkaitan