Apa perbedaan antara array multidimensi double[,]
dan array-of-arraydouble[][]
di C #?
Jika ada perbedaan, apa gunanya yang terbaik untuk masing-masing?
Apa perbedaan antara array multidimensi double[,]
dan array-of-arraydouble[][]
di C #?
Jika ada perbedaan, apa gunanya yang terbaik untuk masing-masing?
double[,]
adalah array persegi panjang, sementaradouble[][]
dikenal sebagai "array bergerigi". Yang pertama akan memiliki jumlah "kolom" yang sama untuk setiap baris, sedangkan yang kedua akan (berpotensi) memiliki jumlah "kolom" yang berbeda untuk setiap baris.Jawaban:
Array array (jagged array) lebih cepat daripada array multi-dimensi dan dapat digunakan lebih efektif. Array multidimensi memiliki sintaks yang lebih bagus.
Jika Anda menulis beberapa kode sederhana menggunakan array bergerigi dan multidimensi dan kemudian memeriksa rakitan yang dikompilasi dengan disassembler IL, Anda akan melihat bahwa penyimpanan dan pengambilan dari array bergerigi (atau dimensi tunggal) adalah instruksi IL sederhana sedangkan operasi yang sama untuk array multidimensi adalah metode doa yang selalu lebih lambat.
Pertimbangkan metode berikut:
IL mereka adalah sebagai berikut:
Saat menggunakan array bergerigi Anda dapat dengan mudah melakukan operasi seperti pertukaran baris dan pengubahan ukuran baris. Mungkin dalam beberapa kasus penggunaan array multidimensi akan lebih aman, tetapi bahkan Microsoft FxCop mengatakan bahwa array bergerigi harus digunakan daripada multidimensi ketika Anda menggunakannya untuk menganalisis proyek Anda.
sumber
Array multidimensi menciptakan tata letak memori linier yang bagus sementara array bergerigi menyiratkan beberapa tingkat tipuan tambahan.
Mencari nilai
jagged[3][6]
dalam array bergerigivar jagged = new int[10][5]
berfungsi seperti ini: Cari elemen pada indeks 3 (yang merupakan array) dan cari elemen pada indeks 6 dalam array itu (yang merupakan nilai). Untuk setiap dimensi dalam kasus ini, ada tampilan tambahan (ini adalah pola akses memori yang mahal).Array multidimensi diletakkan secara linear dalam memori, nilai aktual ditemukan dengan mengalikan indeks-indeks tersebut. Namun, mengingat array
var mult = new int[10,30]
,Length
properti array multidimensi mengembalikan jumlah elemen yaitu 10 * 30 = 300.The
Rank
properti dari array bergerigi selalu 1, tapi array multidimensi dapat memiliki peringkat apapun. TheGetLength
Metode array apapun dapat digunakan untuk mendapatkan panjang masing-masing dimensi. Untuk array multidimensi dalam contoh inimult.GetLength(1)
mengembalikan 30.Mengindeks array multidimensi lebih cepat. misalkan diberi array multidimensi dalam contoh ini
mult[1,7]
= 30 * 1 + 7 = 37, dapatkan elemen pada indeks 37. Ini adalah pola akses memori yang lebih baik karena hanya satu lokasi memori yang terlibat, yang merupakan alamat dasar dari array.Oleh karena itu, array multidimensi mengalokasikan blok memori kontinu, sedangkan array bergerigi tidak harus persegi, misalnya
jagged[1].Length
tidak harus sama denganjagged[2].Length
, yang akan berlaku untuk array multidimensi apa pun.Performa
Dari segi kinerja, array multidimensi harus lebih cepat. Jauh lebih cepat, tetapi karena implementasi CLR yang sangat buruk mereka tidak.
Baris pertama adalah pengaturan array bergerigi, baris kedua menunjukkan array multidimensi dan baris ketiga, yah begitulah seharusnya. Program ditunjukkan di bawah ini, FYI ini diuji menjalankan mono. (Pengaturan waktu windows sangat berbeda, kebanyakan karena variasi implementasi CLR).
Di windows, timing array bergerigi sangat unggul, hampir sama dengan interpretasi saya sendiri tentang seperti apa seharusnya array multidimensi, lihat 'Tunggal ()'. Sayangnya windows JIT-compiler benar-benar bodoh, dan ini sayangnya membuat diskusi kinerja ini sulit, ada terlalu banyak ketidakkonsistenan.
Ini adalah timing yang saya dapatkan di windows, kesepakatan yang sama di sini, baris pertama adalah array bergerigi, multidimensi kedua dan ketiga implementasi multidimensi saya sendiri, perhatikan berapa banyak ini lebih lambat di windows dibandingkan dengan mono.
Kode sumber:
sumber
Sederhananya array multidimensi mirip dengan tabel di DBMS.
Array of Array (jagged array) memungkinkan Anda membuat setiap elemen memiliki array lain dengan jenis panjang variabel yang sama.
Jadi, jika Anda yakin bahwa struktur data terlihat seperti tabel (baris tetap / kolom), Anda dapat menggunakan array multi dimensi. Array bergerigi adalah elemen tetap & setiap elemen dapat memiliki array dengan panjang variabel
Misalnya Psuedocode:
Pikirkan hal di atas sebagai tabel 2x2:
Pikirkan hal di atas karena setiap baris memiliki jumlah variabel kolom:
sumber
Pendahuluan: Komentar ini ditujukan untuk menjawab jawaban yang diberikan oleh okutane , tetapi karena sistem reputasi konyol SO, saya tidak dapat memposting di tempat yang seharusnya.
Pernyataan Anda bahwa yang satu lebih lambat daripada yang lain karena panggilan metode tidak benar. Satu lebih lambat dari yang lain karena algoritma pemeriksaan batas yang lebih rumit. Anda dapat dengan mudah memverifikasi ini dengan melihat, bukan pada IL, tetapi pada majelis yang dikompilasi. Sebagai contoh, pada 4,5 instal saya, mengakses elemen (melalui pointer di edx) disimpan dalam array dua dimensi yang ditunjukkan oleh ecx dengan indeks yang disimpan dalam eax dan edx terlihat seperti ini:
Di sini, Anda dapat melihat bahwa tidak ada overhead dari panggilan metode. Pengecekan batas sangat berbelit-belit berkat kemungkinan indeks yang tidak nol, yang merupakan fungsi yang tidak ditawarkan dengan array bergerigi. Jika kita menghapus sub, cmp, dan jmps untuk case-case yang bukan nol, kode ini cukup banyak untuk dipecahkan
(x*y_max+y)*sizeof(ptr)+sizeof(array_header)
. Penghitungan ini kira-kira sama cepat (satu kali lipat dapat diganti dengan shift, karena itulah alasan utama kami memilih byte untuk diukur sebagai kekuatan dua bit) seperti yang lainnya untuk akses acak ke suatu elemen.Komplikasi lain adalah bahwa ada banyak kasus di mana kompiler modern akan mengoptimalkan jauh memeriksa batas-batas untuk akses elemen sambil iterasi melalui array satu dimensi. Hasilnya adalah kode yang pada dasarnya hanya memajukan penunjuk indeks ke memori yang berdekatan dari array. Iterasi naif atas array multi-dimensi umumnya melibatkan lapisan tambahan dari logika bersarang, sehingga kompiler cenderung mengoptimalkan operasi. Jadi, meskipun overhead-memeriksa batas mengakses elemen tunggal diamortisasi ke runtime konstan sehubungan dengan dimensi dan ukuran array, kasus uji sederhana untuk mengukur perbedaan mungkin membutuhkan waktu beberapa kali lebih lama untuk dieksekusi.
sumber
Saya ingin memperbarui ini, karena dalam . Core Core multi-dimensi array lebih cepat daripada array bergerigi . Saya menjalankan tes dari John Leidegren dan ini adalah hasil pada .NET Core 2.0 preview 2. Saya meningkatkan nilai dimensi untuk membuat pengaruh yang mungkin dari aplikasi latar belakang kurang terlihat.
Saya melihat ke pembongkaran dan ini adalah apa yang saya temukan
jagged[i][j][k] = i * j * k;
dibutuhkan 34 instruksi untuk dieksekusimulti[i, j, k] = i * j * k;
diperlukan 11 instruksi untuk dieksekusisingle[i * dim * dim + j * dim + k] = i * j * k;
dibutuhkan 23 instruksi untuk dieksekusiSaya tidak dapat mengidentifikasi mengapa array satu dimensi masih lebih cepat daripada multi-dimensi tetapi dugaan saya adalah bahwa itu ada hubungannya dengan beberapa optimasi yang dilakukan pada CPU.
sumber
Array multi-dimensi adalah (n-1) matriks -dimensi.
Begitu
int[,] square = new int[2,2]
juga matriks persegi 2x2,int[,,] cube = new int [3,3,3]
adalah matriks kubus - persegi 3x3. Tidak perlu proporsionalitas.Array bergerigi hanya array array - array di mana setiap sel berisi array.
Jadi MDA proporsional, JD mungkin tidak! Setiap sel dapat berisi array dengan panjang sewenang-wenang!
sumber
Ini mungkin telah disebutkan dalam jawaban di atas tetapi tidak secara eksplisit: dengan jagged array yang dapat Anda gunakan
array[row]
untuk merujuk seluruh baris data, tetapi ini tidak diperbolehkan untuk array multi-d.sumber
Selain jawaban lain, perhatikan bahwa array multidimensi dialokasikan sebagai satu objek tebal besar di heap. Ini memiliki beberapa implikasi:
<gcAllowVeryLargeObjects>
array multidimensi sebelum masalah akan pernah muncul jika Anda hanya menggunakan array bergerigi.sumber
Saya mem-parsing file .il yang dihasilkan oleh ildasm untuk membangun database assemnblies, kelas, metode, dan prosedur tersimpan untuk digunakan melakukan konversi. Saya menemukan yang berikut, yang mematahkan parsing saya.
Buku Expert .NET 2.0 IL Assembler, oleh Serge Lidin, Apress, yang diterbitkan tahun 2006, Bab 8, Primitive Types and Signatures, hlm. 149-150 menjelaskan.
<type>[]
disebut sebagai Vektor dari<type>
,<type>[<bounds> [<bounds>**] ]
disebut array<type>
**
berarti dapat diulang,[ ]
berarti opsional.Contoh: Biarkan
<type> = int32
.1)
int32[...,...]
adalah susunan dua dimensi dari batas bawah dan ukuran yang tidak ditentukan2)
int32[2...5]
adalah array satu dimensi dari batas bawah 2 dan ukuran 4.3)
int32[0...,0...]
adalah susunan dua dimensi dengan batas bawah 0 dan ukuran tidak terdefinisi.Tom
sumber