Apakah ada manfaat menggunakan variabel tambahan ini dalam anotasi for loop?

11

Saya telah menemukan anotasi loop berikut dalam proyek besar yang sedang saya kerjakan (pseudocode):

var someOtherArray = [];
for (var i = 0, n = array.length; i < n; i++) {
    someOtherArray[i] = modifyObjetFromArray(array[i]);
}

Yang menarik perhatian saya adalah variabel "n" ekstra ini. Saya belum pernah melihat for a lop ditulis dengan cara ini sebelumnya.

Jelas dalam skenario ini tidak ada alasan mengapa kode ini tidak dapat ditulis dengan cara berikut (yang saya sudah sangat terbiasa):

var someOtherArray = [];
for (var i = 0; i < array.length; i++) {
    someOtherArray[i] = modifyObjetFromArray(array[i]);
}

Tapi itu membuat saya berpikir.

Apakah ada skenario ketika menulis loop for seperti itu masuk akal? Ide terlintas dalam pikiran bahwa panjang "array" dapat berubah selama eksekusi loop, tetapi kami tidak ingin mengulang lebih jauh dari ukuran aslinya, tetapi saya tidak dapat membayangkan skenario seperti itu.

Mengecilkan array di dalam loop juga tidak masuk akal, karena kita cenderung mendapatkan OutOfBoundsException.

Apakah ada pola desain yang diketahui di mana anotasi ini bermanfaat?

Sunting Seperti dicatat oleh @ Jerry101 alasannya adalah kinerja. Berikut ini tautan ke tes kinerja yang telah saya buat: http://jsperf.com/ninforloop . Menurut pendapat saya perbedaannya tidak cukup besar kecuali Anda iterasi meskipun array yang sangat besar. Kode yang saya salin dari hanya memiliki hingga 20 elemen, jadi saya pikir keterbacaan dalam kasus ini melebihi pertimbangan kinerja.

Vlad Spreys
sumber
Sebagai reaksi terhadap Anda mengedit: ini adalah pemrograman berorientasi objek. Array standar. Panjangnya cepat dan murah. Tapi untuk alasan apa pun, penerapan .length bisa berubah menjadi sesuatu yang mahal. Jika suatu nilai tetap sama maka jangan mendapatkannya berulang kali.
Pieter B
Saya setuju. Ada baiknya untuk mengetahui tentang opsi ini, tetapi saya mungkin tidak akan sering menggunakannya, kecuali saya mendapatkan contoh yang mirip dengan permintaan sql Anda. Terima kasih☺
Vlad Spreys
Masalahnya, jika array Anda adalah sejuta item, Anda akan memanggil array. Panjang satu juta kali, bukan 1 kali sementara nilainya tetap sama. Menanyakan sesuatu sejuta kali dan mengetahui bahwa setiap jawaban berikutnya akan sama dengan jawaban pertama ...... hanya terdengar sedikit tidak masuk akal bagi saya.
Pieter B
1
Saya tidak menemukan ini membuat kode secara signifikan lebih sulit untuk dibaca. (Serius, jika ada yang mengalami masalah dengan loop sederhana seperti itu, mereka harus khawatir.) Tetapi: 1) Saya akan sangat terkejut jika setelah 4 dekade bahasa C dan C-turun, setiap kompiler serius belum melakukan ini untukmu; dan 2) ini mungkin bukan hot spot. Tampaknya tidak layak membuat seseorang menghabiskan 5 detik tambahan untuk menguraikannya kecuali itu ada di dalam perpustakaan (mis. Implementasi struktur data.)
Doval
1
Dalam C # /. NET varian menggunakan nmungkin lebih lambat daripada menggunakan varian array.Lengthkarena JITter mungkin tidak melihat bahwa itu bisa menghilangkan cek batas array.
CodesInChaos

Jawaban:

27

Variabel nmemastikan kode yang dihasilkan tidak mengambil panjang array untuk setiap iterasi.

Ini merupakan pengoptimalan yang dapat membuat perbedaan dalam jangka waktu berjalan tergantung pada bahasa yang digunakan, apakah array tersebut sebenarnya adalah objek koleksi atau "array" JavaScript, dan detail pengoptimalan lainnya.

Jerry101
sumber
3
Tidak, tidak. Apakah panjang array diambil setiap iterasi tidak hanya bergantung pada bahasa, tetapi juga pada kompiler dan opsi kompiler dan apa yang dilakukan dalam loop (saya berbicara tentang C dan C ++)
BЈовић
.. Dan meskipun demikian, saya pribadi akan menempatkan tugas n tepat di atas loop jika saya benar-benar menginginkannya, karena - seperti OP catat - ini adalah konstruksi (YMMV) yang jarang digunakan dan mudah dilewatkan / tidak dipahami oleh pengembang dev lainnya. Kode.
cwap
20
Seperti yang tertulis, itu lingkup nke loop, yang biasanya merupakan hal yang baik. Saya akan mendefinisikannya sebelum loop hanya jika saya ingin menggunakannya lagi nanti.
Jerry101
4
@ Jerry101: Rupanya contoh cuplikannya adalah JavaScript, di mana tidak ada yang namanya lingkup loop ...
Bergi
1
@ BЈовић: dalam praktiknya, kompiler jarang berhasil membuktikan bahwa ukuran array tidak bervariasi (biasanya itu hanya dapat dibuktikan secara sepele jika vektor yang Anda lewati adalah lokal ke fungsi dan Anda hanya memanggil fungsi-fungsi yang digarisbawahi dalam loop).
Matteo Italia
2

Pengambilan panjang array dapat dengan mudah menjadi "lebih mahal" daripada tindakan aktual yang Anda lakukan berulang kali.

Jadi jika set tidak berubah, hanya kueri panjangnya sekali.

Tidak dengan array, tetapi dengan set-set rekaman yang berasal dari server sql saya telah melihat peningkatan dramatis dengan tidak menanyakan jumlah-catatan setiap iterasi. (tentu saja lakukan ini hanya jika Anda dapat menjamin Anda array atau set-record tidak berubah selama proses ini).

Pieter B
sumber
Jika jumlah catatan berubah, lalu apa? Katakan ada 100 item, dan saat Anda memproses item 50, item setelah # 25 dimasukkan. Jadi ketika Anda memproses item # 51, itu sama dengan # 50 yang sudah Anda proses, dan ada yang salah. Jadi masalahnya bukan perubahan panjang itu, itu jauh lebih luas.
gnasher729
@ gnasher729 begitu Anda masuk ke perilaku asimetris, ada banyak hal yang bisa salah. Tetapi ada hal-hal yang dapat Anda lakukan terhadap itu seperti memulai dan sql transaksi.
Pieter B
2

Ide terlintas dalam pikiran bahwa panjang "array" dapat berubah selama eksekusi loop, tetapi kami tidak ingin mengulang lebih jauh dari ukuran aslinya, tetapi saya tidak dapat membayangkan skenario seperti itu.

Orang-orang yang berbicara tentang kinerja mungkin benar bahwa inilah sebabnya mengapa ditulis demikian (orang yang menulisnya dengan cara itu mungkin tidak benar bahwa itu secara signifikan memengaruhi kinerja, tetapi itu masalah lain).

Namun, untuk menjawab bagian dari pertanyaan Anda ini, saya pikir itu paling mungkin terjadi ketika tujuan utama loop adalah untuk memodifikasi array yang berulang. Pertimbangkan sesuatu seperti ini, dalam pseudo-code:

guests = [];
for (i = 0; i < invitations.length; ++i) {
    if (! invitations[i].is_declined()) {
        guests.append(invitations[i].recipient())
    }
}
// maybe some other stuff to modify the guestlist
for (i = 0, n = guests.length; i < n; ++i) {
    if (guests[i].has_plus_one()) {
        guests.append(guests[i].get_plus_one());
    }
}

Tentu saja ada cara lain untuk menulisnya. Dalam hal ini saya bisa mengecek untuk plus pada saat yang sama dengan memeriksa apakah penerima menerima undangan mereka, dan menghasilkan daftar tamu lengkap satu undangan pada suatu waktu. Saya tidak perlu ingin menggabungkan kedua operasi itu, tetapi saya tidak dapat segera memikirkan alasan mengapa itu pasti salah dan oleh karena itu desain ini diperlukan . Ini merupakan opsi untuk dipertimbangkan, sesekali.

Sebenarnya saya pikir hal yang paling salah dengan kode ini adalah keanggotaan guestsarray memiliki arti berbeda pada titik berbeda dalam kode. Karena itu saya tentu tidak akan menyebutnya "pola", tapi saya tidak tahu bahwa itu cukup cacat untuk mengesampingkan pernah melakukan hal semacam ini :-)

Steve Jessop
sumber
Array juga dapat dimodifikasi oleh utas lainnya. Ini mencegah kompiler mengoptimalkan pencarian panjang. Jadi yang dimaksud, programmer secara eksplisit mengatakan bahwa array tidak berubah bahkan di utas lainnya.
Basilevs
0

Jika memungkinkan, Anda harus menggunakan iterator yang melintasi semua elemen array. Anda menggunakan array hanya sebagai urutan, bukan sebagai penyimpanan akses-acak, jadi akan jelas bahwa iterator yang hanya melakukan akses sekuensial akan lebih cepat. Bayangkan apa yang Anda pikir array sebenarnya adalah pohon biner, tetapi seseorang telah menulis kode yang menentukan "panjang" dengan menghitung elemen, dan kode yang mengakses elemen ke-i, juga dengan melintasi elemen, masing-masing dalam O (n ). Sebuah iterator bisa sangat cepat, loop Anda akan menjadi sloooooow.

gnasher729
sumber