Ketika kita berbicara tentang array, biasanya yang kita maksud adalah vektor dari sesuatu – primitif, objek, atau bahkan array. Tetapi ada banyak situasi ketika kita perlu membawa informasi tambahan dengan data kita. Kita dapat menggunakan array bersarang tetapi tidak menyebabkan item spesifik dalam array akan mudah diidentifikasi. Untuk mencapainya kita harus menggunakan kunci khusus. Mereka menyediakan akses mudah ke setiap elemen array selama kita mengetahui kunci yang sesuai dengan nilai tersebut
Ada beberapa alasan mengapa kita dapat menggunakan array asosiatif daripada vektor sederhana, mis. g. keterbacaan. Kunci bernama juga lebih bermakna daripada indeks numerik. Alih-alih memikirkan mengapa, bayangkan situasi saat kita bisa menggunakan peta hash. Mari fokus pada bagaimana kita dapat membangun array asosiatif dari sebuah vektor
Contoh skenario
Dalam aplikasi kami, kami memiliki pengguna dari berbagai belahan dunia. Selama proses pendaftaran, pengguna dapat memilih negaranya sendiri. Dalam database kami, kami menyimpan informasi tentang negara dalam format ISO-3361-alpha-1. Pengguna seharusnya melihat nama lengkap negara sebagai gantinya
Kami sebenarnya memiliki array Country
objek, yang definisinya disajikan di bawah ini
class Country
{
private $name;
private $code;
public function __construct[string $name, string $code]
{
$this->name = $name;
$this->code = $code;
}
public function getName[]: string
{
return $this->name;
}
public function getCode[]: string
{
return $this->code;
}
}
Salah satu komponen frontend kami dapat merender Combo
[dikenal sebagai node] dan mengharapkan array asosiatif sebagai input dalam format
['value' => 'text visible for user']
Kita perlu membuat array ini
Pendekatan #0. lingkaran dasar
function prepareCountriesForCombo[array $countries]: array
{
$output = [];
foreach [$countries as $country] {
$output[$country->getCode[]] = $country->getName[];
}
return $output;
}
$countriesSelect = prepareCountriesForCombo[$countries];
_Pendekatan paling dasar yang saya tahu. Saya sering mempertanyakan solusi yang menggunakan loop mentah karena mereka adalah makhluk level rendah. Tetapi jika mereka dikemas dalam fungsi yang dijelaskan dengan baik, itu adalah O. K
Membuat fungsi yang dirancang untuk menghasilkan data spesifik untuk komponen lain tampaknya merupakan ide yang bagus. Mari pertimbangkan bahwa kita perlu mengirim data ke Combo
yang berbeda. Alangkah baiknya menggunakan fungsi yang sama tetapi dengan data yang berbeda. Saya perlu menggeneralisasi pendekatan ini
Pendekatan #1. Cara generik untuk menghasilkan array asosiatif
Selain array yang berisi data, kita perlu melewatkan dua fungsi tambahan. Yang pertama akan bertanggung jawab untuk mengubah elemen menjadi teks yang terlihat oleh pengguna dan yang terakhir akan mengubah elemen menjadi kunci peta asosiatif
Fungsinya bisa terlihat seperti ini
function mapForCombo[array $array, Closure $fnValue, Closure $fnKey]: array
{
$output = [];
foreach [$array as $element] {
$output[$fnKey[$element]] = $fnValue[$element];
}
return $output;
}
$countriesSelect = mapForCombo[
$countries,
function [Country $country] { return $country->getCode[]; },
function [Country $country] { return $country->getName[]; }
];
Kelihatannya cukup bagus dan mungkin kita harus berhenti membahas lebih lanjut tentang fitur yang membosankan ini. Lagi pula, mari kita coba mencari implementasi lain untuk kasus khusus ini
Pendekatan #2. menggunakan fungsi peta array
Saya sangat suka fungsi array. Mereka sangat kuat. Kita dapat mengubah kunci dan nilai dari array asosiatif secara mandiri dan kita dapat menggabungkannya menjadi satu array
function mapForCombo[array $array, Closure $fnValue, Closure $fnKey]: array
{
$keys = array_map[$fnKey, $array];
$values = array_map[$fnValue, $array];
return array_combine[$keys, $values];
}
$countriesSelect = mapForCombo[
$countries,
function [Country $country] { return $country->getCode[]; },
function [Country $country] { return $country->getName[]; }
];
Kodenya jauh lebih pendek, tetapi di balik terpal, PHP memiliki lebih banyak pekerjaan. Meskipun tidak ada loop yang terlihat di userland, mesin PHP harus mengulang array setidaknya 3 kali [dua kali untuk peta dan sekali untuk digabungkan]. Tampaknya lambat dan tidak begitu efisien
Pendekatan 3. peta array dengan mengurangi
Pendekatan berikutnya mungkin menggunakan fungsi
function prepareCountriesForCombo[array $countries]: array
{
$output = [];
foreach [$countries as $country] {
$output[$country->getCode[]] = $country->getName[];
}
return $output;
}
$countriesSelect = prepareCountriesForCombo[$countries];
_1, bukan pemetaan. Apa fungsi ini sebenarnya saya jelaskan di salah satu posting saya sebelumnya. Sederhananya, pendekatan ini adalah untuk mengurangi array menjadi nilai tunggal. Tapi tidak ada yang mengatakan bahwa nilai tunggal tidak bisa berupa arrayfunction mapForCombo[array $array, Closure $fnValue, Closure $fnKey]: array
{
return array_reduce[$array, function [$acc, $element] use [$fnKey, $fnValue] {
$acc[$fnKey[$element]] = $fnValue[$element];
return $acc;
}, []];
}
$countriesSelect = mapForCombo[
$countries,
function [Country $country] { return $country->getCode[]; },
function [Country $country] { return $country->getName[]; }
];
Satu-satunya hal yang harus kita lakukan adalah membuat fungsi yang akan menetapkan nilai yang diubah ke kunci tertentu dalam array [mirip dengan pendekatan pertama]. Logika loop disembunyikan di dalam fungsi
function prepareCountriesForCombo[array $countries]: array
{
$output = [];
foreach [$countries as $country] {
$output[$country->getCode[]] = $country->getName[];
}
return $output;
}
$countriesSelect = prepareCountriesForCombo[$countries];
_1 jadi hanya peduli dengan penugasan yang benarSolusi mana yang lebih baik?
Tes
Secara pribadi, saya tidak suka melakukan dan membaca tolok ukur untuk hal-hal yang biasanya tidak penting. Kalau tidak, saya mengumpulkan beberapa ide dan saya ingin memvalidasinya sedemikian rupa. Itu sebabnya saya menguji implementasi mana yang bekerja lebih cepat
Uji file dan lingkungan
Saya menyiapkan file pengujian sederhana, Anda dapat melihatnya di GitHub Gist ini. Meskipun tidak begitu rumit, cukup melihat implementasi mana yang lebih baik, relatif satu sama lain. Singkatnya – saya menjalankan setiap fungsi 5000 kali dan saya mengukur durasi eksekusi
Pertama saya mencoba menjalankan skrip ini di lingkungan lokal saya, tetapi saya sampai pada kesimpulan, bahwa opsi bettser adalah menggunakan server yang sama sekali berbeda. Saya menyewa droplet 2GB RAM / 2 CPU dari DigitalOcean yang siap pakai LAMP Stack on board dan saya menjalankan tes
root@lamp-2gb-nyc3-01:~# php -v
PHP 7.0.22-0ubuntu0.16.04.1 [cli] [ NTS ]
Tes menghasilkan output yang saya salin dan tempel sebagai CSV ke Excel. Ini memungkinkan saya untuk dengan mudah menghitung waktu rata-rata dan memplot bagan sederhana
Hasil tes
Harus saya akui, hasil itu sangat mengejutkan saya. Pertama, silakan lihat hasil akhirnya
- Pendekatan #1 –
_3 – 0,283 detikfunction prepareCountriesForCombo[array $countries]: array { $output = []; foreach [$countries as $country] { $output[$country->getCode[]] = $country->getName[]; } return $output; } $countriesSelect = prepareCountriesForCombo[$countries];
- Pendekatan #2 –
_4 – 0,253 detikfunction prepareCountriesForCombo[array $countries]: array { $output = []; foreach [$countries as $country] { $output[$country->getCode[]] = $country->getName[]; } return $output; } $countriesSelect = prepareCountriesForCombo[$countries];
- Pendekatan #3 –
_1 – 1.054 detikfunction prepareCountriesForCombo[array $countries]: array { $output = []; foreach [$countries as $country] { $output[$country->getCode[]] = $country->getName[]; } return $output; } $countriesSelect = prepareCountriesForCombo[$countries];
Perbedaan lebih terlihat pada diagram batang sederhana
Kesan pertama saya adalah seperti campuran kebingungan dengan kesalahpahaman. Solusi yang tampaknya menjadi yang terbaik ternyata, yang paling tidak efisien. Ini menunjukkan, bahwa kita harus selalu menguji dan memvalidasi ide kita
Saya pribadi cukup sering menggunakan pendekatan
function prepareCountriesForCombo[array $countries]: array
{
$output = [];
foreach [$countries as $country] {
$output[$country->getCode[]] = $country->getName[];
}
return $output;
}
$countriesSelect = prepareCountriesForCombo[$countries];
1. Untungnya, tes tersebut sengaja dilebih-lebihkan untuk menunjukkan perbedaan antara masing-masing pendekatan. Untuk kumpulan data yang lebih kecil, perbedaannya tidak terlihatItu tidak berarti, bahwa Anda tidak boleh menggunakan fungsi
function prepareCountriesForCombo[array $countries]: array
{
$output = [];
foreach [$countries as $country] {
$output[$country->getCode[]] = $country->getName[];
}
return $output;
}
$countriesSelect = prepareCountriesForCombo[$countries];
1. Ini memiliki kasus dan makna penggunaan khusus jadi jangan ragu untuk menggunakan fungsi ini jika memenuhi kebutuhan AndaRingkasan
Saya tidak yakin, apakah eksperimen ini akan mengubah cara saya menulis kode. Sejujurnya, ini hanya optimasi mikro dalam skala yang lebih besar. Meskipun terkadang itu penting, e. g. jika Anda harus menulis algoritme dengan efisiensi tinggi, bagi kebanyakan dari kita itu hanya masalah yang tidak perlu
Kalau tidak, itu mengungkapkan sesuatu yang sama sekali berbeda. Kami percaya bahwa hal-hal bekerja lebih cepat karena tampaknya menjadi lebih cepat. Mereka mengeksekusi lebih sedikit loop dan mengandung logika dan kondisi yang jauh lebih rumit. Contoh ini menunjukkan bahwa tidak ada kebenaran dalam semua kasus
Seperti yang Anda perhatikan, tidak ada aturan emas tentang cara mengubah data ke array asosiatif. Kesederhanaan adalah kuncinya, tetapi kita harus selalu menguji, mengonfirmasi, dan membandingkan solusi kita dengan yang lain. Ini bukan hanya tentang transformasi array tetapi juga tentang banyak hal lainnya. Mungkin solusi Anda berikutnya akan lebih baik, lebih mudah, dan lebih cepat?