Aturan praktisnya adalah menggunakan fungsi yang paling sesuai dengan kebutuhan Anda.
Jika Anda hanya menginginkan kunci dan tidak berencana untuk membaca nilai apa pun, gunakan keys ():
foreach my $key (keys %hash) { ... }
Jika Anda hanya ingin nilainya, gunakan values ():
foreach my $val (values %hash) { ... }
Jika Anda membutuhkan kunci dan nilainya, gunakan each ():
keys %hash; # reset the internal iterator so a prior each() doesn't affect the loop
while(my($k, $v) = each %hash) { ... }
Jika Anda berencana untuk mengubah kunci hash dengan cara apapun kecuali untuk menghapus kunci saat ini selama iterasi, maka Anda tidak boleh menggunakan each (). Misalnya, kode ini untuk membuat satu set baru kunci huruf besar dengan nilai ganda berfungsi dengan baik menggunakan keys ():
%h = (a => 1, b => 2);
foreach my $k (keys %h)
{
$h{uc $k} = $h{$k} * 2;
}
menghasilkan hash yang diharapkan:
(a => 1, A => 2, b => 2, B => 4)
Tetapi menggunakan each () untuk melakukan hal yang sama:
%h = (a => 1, b => 2);
keys %h;
while(my($k, $v) = each %h)
{
$h{uc $k} = $h{$k} * 2; # BAD IDEA!
}
menghasilkan hasil yang salah dengan cara yang sulit diprediksi. Sebagai contoh:
(a => 1, A => 2, b => 2, B => 8)
Namun, ini aman:
keys %h;
while(my($k, $v) = each %h)
{
if(...)
{
delete $h{$k}; # This is safe
}
}
Semua ini dijelaskan dalam dokumentasi perl:
% perldoc -f keys
% perldoc -f each
Satu hal yang harus Anda waspadai saat menggunakan
each
adalah bahwa ia memiliki efek samping menambahkan "status" ke hash Anda (hash harus mengingat kunci "berikutnya"). Saat menggunakan kode seperti cuplikan yang diposting di atas, yang mengulang seluruh hash sekaligus, ini biasanya tidak menjadi masalah. Namun, Anda akan mengalami kesulitan untuk melacak masalah (saya berbicara dari pengalaman;), ketika menggunakaneach
bersama dengan pernyataan sukalast
ataureturn
keluar dariwhile ... each
loop sebelum Anda memproses semua kunci.Dalam kasus ini, hash akan mengingat kunci mana yang telah dikembalikan, dan ketika Anda menggunakannya
each
di lain waktu (mungkin dalam bagian kode yang sama sekali tidak terkait), hash akan berlanjut pada posisi ini.Contoh:
Ini mencetak:
Apa yang terjadi dengan kunci "bar" dan baz "? Mereka masih ada, tapi yang kedua
each
dimulai dari yang pertama berhenti, dan berhenti ketika mencapai akhir hash, jadi kita tidak pernah melihatnya di loop kedua.sumber
Tempat di mana
each
dapat menyebabkan masalah bagi Anda adalah bahwa ini adalah iterator non-cakupan yang benar. Sebagai contoh:Jika Anda perlu memastikan bahwa
each
mendapatkan semua kunci dan nilai, Anda perlu memastikan Anda menggunakankeys
atauvalues
terlebih dahulu (karena itu menyetel ulang iterator). Lihat dokumentasi untuk masing-masing .sumber
Menggunakan setiap sintaks akan mencegah seluruh rangkaian kunci dibuat sekaligus. Ini bisa menjadi penting jika Anda menggunakan hash terkait ke database dengan jutaan baris. Anda tidak ingin membuat seluruh daftar kunci sekaligus dan menghabiskan memori fisik Anda. Dalam hal ini masing-masing berfungsi sebagai iterator sedangkan kunci sebenarnya menghasilkan seluruh array sebelum loop dimulai.
Jadi, satu-satunya tempat "setiap" yang benar-benar digunakan adalah saat hash sangat besar (dibandingkan dengan memori yang tersedia). Itu hanya mungkin terjadi ketika hash itu sendiri tidak tinggal di memori itu sendiri kecuali Anda memprogram perangkat pengumpulan data genggam atau sesuatu dengan memori kecil.
Jika memori tidak menjadi masalah, biasanya paradigma peta atau kunci adalah paradigma yang lebih umum dan lebih mudah dibaca.
sumber
Beberapa pemikiran lain tentang topik ini:
values
mengembalikan alias yang berarti bahwa memodifikasinya akan mengubah konten hash. Ini memang disengaja tetapi mungkin bukan yang Anda inginkan dalam beberapa keadaan.each
. Ini tidak benar karenakeys
sebagaieach
iterator saatkeys
mengembalikan daftar.sumber
Saya selalu menggunakan metode 2 juga. Satu-satunya manfaat menggunakan masing-masing adalah jika Anda hanya membaca (daripada menetapkan ulang) nilai entri hash, Anda tidak terus-menerus membatalkan referensi hash.
sumber
Saya mungkin akan digigit oleh yang satu ini tetapi saya pikir itu adalah preferensi pribadi. Saya tidak dapat menemukan referensi apa pun di dokumen untuk setiap () berbeda dari kunci () atau nilai () (selain jawaban yang jelas "mereka mengembalikan hal yang berbeda". Faktanya, dokumen menyatakan penggunaan iterator yang sama dan semuanya mengembalikan nilai daftar sebenarnya alih-alih menyalinnya, dan bahwa memodifikasi hash saat mengulanginya menggunakan panggilan apa pun itu buruk.
Semua yang dikatakan, saya hampir selalu menggunakan keys () karena bagi saya biasanya lebih mendokumentasikan diri untuk mengakses nilai kunci melalui hash itu sendiri. Saya kadang-kadang menggunakan values () ketika nilainya adalah referensi ke struktur besar dan kunci hash sudah disimpan dalam struktur, pada titik mana kuncinya berlebihan dan saya tidak membutuhkannya. Saya pikir saya telah menggunakan masing-masing () 2 kali dalam 10 tahun pemrograman Perl dan itu mungkin pilihan yang salah keduanya =)
sumber
Saya biasanya menggunakan
keys
dan saya tidak dapat memikirkan kapan terakhir kali saya menggunakan atau membaca penggunaaneach
.Jangan lupa
map
, tergantung pada apa yang Anda lakukan dalam loop!sumber
Saya akan mengatakan:
Ini memberikan 2 keuntungan utama:
Menurut saya tidak lebih mahal menggunakan kunci untuk masing-masing, jadi tidak perlu dua konstruksi berbeda untuk hal yang sama dalam kode Anda.
sumber
keys
penggunaan memori meningkathash-size * avg-key-size
. Mengingat bahwa ukuran kunci hanya dibatasi oleh memori (karena mereka hanya elemen larik seperti nilai yang sesuai "mereka" di bawah tenda), dalam beberapa situasi, ini bisa menjadi sangat mahal baik dalam penggunaan memori dan waktu yang dibutuhkan untuk membuat salinan.