Apa spesifik kebutuhan Anda? Apakah Anda mengambil penyatuan array atau Anda mempertahankan beberapa instance dengan nilai yang sama? Apakah Anda ingin item diurutkan, atau Anda ingin mempertahankan pemesanan di array awal? Apakah Anda mencari efisiensi dalam kecepatan atau dalam baris kode?
jason
Menyukainya, "terbaik" tergantung pada apa kebutuhan Anda.
Ady
7
Jika Anda dapat menggunakan LINQ, maka Anda hanya dapat menggunakan Concatmetode:IEnumerable<byte> arrays = array1.Concat(array2).Concat(array3);
casperOne
1
Cobalah untuk lebih jelas dalam pertanyaan Anda. Pertanyaan samar ini telah menyebabkan banyak kebingungan di antara orang-orang yang cukup baik untuk meluangkan waktu untuk menjawab Anda.
Tapi, jika Anda bisa menggunakan metode IEnumerable<byte>, PASTI lebih suka metode LINQ Concat <>. Ini hanya sedikit lebih lambat dari operator hasil C #, tetapi lebih ringkas dan lebih elegan.
IEnumerable<byte> rv = a1.Concat(a2).Concat(a3);
Jika Anda memiliki jumlah array yang sewenang-wenang dan menggunakan .NET 3.5, Anda dapat membuat System.Buffer.BlockCopysolusinya lebih umum seperti ini:
* Catatan: Blok di atas mengharuskan Anda menambahkan namespace berikut di bagian atas agar bisa berfungsi.
using System.Linq;
Untuk poin Jon Skeet mengenai iterasi dari struktur data berikutnya (byte array vs IEnumerable <byte>), saya menjalankan kembali tes waktu terakhir (1 juta elemen, 4000 iterasi), menambahkan loop yang mengulangi array penuh dengan masing-masing lulus:
Array Byte Baru menggunakan System.Array.Copy - 78,20550510 detik
Array Byte Baru menggunakan System.Buffer.BlockCopy - 77,89261900 detik
IEnumerable <byte> menggunakan operator hasil C # - 551.7150161 detik
IEnumerable <byte> menggunakan LINQ's Concat <> - 448.1804799 detik
Intinya adalah, SANGAT penting untuk memahami efisiensi penciptaan dan penggunaan struktur data yang dihasilkan. Dengan hanya berfokus pada efisiensi penciptaan dapat mengabaikan inefisiensi yang terkait dengan penggunaan. Salam, Jon.
Tetapi apakah Anda benar-benar mengubahnya menjadi sebuah array di akhir, seperti pertanyaannya? Jika tidak, tentu saja lebih cepat - tetapi tidak memenuhi persyaratan.
Jon Skeet
18
Re: Matt Davis - Tidak masalah jika "persyaratan" Anda perlu mengubah IEnumerable menjadi sebuah array - semua yang Anda butuhkan adalah bahwa hasilnya benar-benar digunakan dalam beberapa fasion . Alasan mengapa tes kinerja Anda pada IEnumerable sangat rendah adalah karena Anda sebenarnya tidak melakukan apa-apa ! LINQ tidak melakukan pekerjaannya sampai Anda mencoba menggunakan hasilnya. Untuk alasan ini, saya menemukan jawaban Anda secara objektif salah dan dapat membuat orang lain menggunakan LINQ padahal sebenarnya mereka tidak perlu jika mereka peduli dengan kinerja.
csauve
12
Saya membaca seluruh jawaban termasuk pembaruan Anda, komentar saya berdiri. Saya tahu saya terlambat datang ke pesta, tetapi jawabannya terlalu menyesatkan dan setengahnya benar - benar salah .
csauve
14
Mengapa jawaban yang berisi informasi yang salah dan menyesatkan merupakan jawaban yang dipilih, dan diedit pada dasarnya benar - benar membatalkan pernyataan aslinya setelah seseorang (Jon Skeet) menunjukkan bahwa itu bahkan tidak menjawab pertanyaan OP?
MrCC
3
Jawaban yang menyesatkan. Bahkan edisi ini tidak menjawab pertanyaan.
Serge Profafilecebook
154
Banyak jawaban bagi saya tampaknya mengabaikan persyaratan yang dinyatakan:
Hasilnya harus berupa array byte
Itu harus seefisien mungkin
Keduanya bersama-sama mengesampingkan urutan byte LINQ - apa pun dengan yieldakan membuat tidak mungkin untuk mendapatkan ukuran akhir tanpa iterasi melalui seluruh urutan.
Jika itu bukan persyaratan nyata tentunya, LINQ bisa menjadi solusi yang sangat baik (atau IList<T>implementasinya). Namun, saya akan berasumsi bahwa Superdumbell tahu apa yang dia inginkan.
(EDIT: Saya baru saja berpikir lain. Ada perbedaan besar antara membuat salinan array dan membacanya dengan malas. Pertimbangkan apa yang terjadi jika Anda mengubah data di salah satu array "sumber" setelah memanggil Combine(atau apa pun) ) tetapi sebelum menggunakan hasilnya - dengan evaluasi malas, perubahan itu akan terlihat. Dengan salinan langsung, itu tidak akan. Situasi yang berbeda akan memerlukan perilaku yang berbeda - hanya sesuatu yang harus diperhatikan.)
Berikut adalah metode yang saya usulkan - yang sangat mirip dengan yang terkandung dalam beberapa jawaban lain, tentu saja :)
publicstaticbyte[]Combine(byte[] first,byte[] second){byte[] ret =newbyte[first.Length+ second.Length];Buffer.BlockCopy(first,0, ret,0, first.Length);Buffer.BlockCopy(second,0, ret, first.Length, second.Length);return ret;}publicstaticbyte[]Combine(byte[] first,byte[] second,byte[] third){byte[] ret =newbyte[first.Length+ second.Length+ third.Length];Buffer.BlockCopy(first,0, ret,0, first.Length);Buffer.BlockCopy(second,0, ret, first.Length, second.Length);Buffer.BlockCopy(third,0, ret, first.Length+ second.Length,
third.Length);return ret;}publicstaticbyte[]Combine(paramsbyte[][] arrays){byte[] ret =newbyte[arrays.Sum(x => x.Length)];int offset =0;foreach(byte[] data in arrays){Buffer.BlockCopy(data,0, ret, offset, data.Length);
offset += data.Length;}return ret;}
Tentu saja versi "params" membutuhkan pembuatan array array byte terlebih dahulu, yang memperkenalkan inefisiensi tambahan.
Jon, aku mengerti persis apa yang kamu katakan. Satu-satunya poin saya adalah bahwa kadang-kadang pertanyaan diajukan dengan implementasi tertentu sudah ada dalam pikiran tanpa menyadari bahwa ada solusi lain. Cukup memberikan jawaban tanpa menawarkan alternatif sepertinya merugikan saya. Pikiran?
Matt Davis
1
@Matt: Ya, menawarkan alternatif itu baik - tetapi perlu dijelaskan bahwa itu adalah alternatif daripada meneruskannya sebagai jawaban atas pertanyaan yang diajukan. (Saya tidak mengatakan bahwa Anda melakukan itu - jawaban Anda sangat bagus.)
Jon Skeet
4
(Meskipun saya pikir patokan kinerja Anda harus menunjukkan waktu yang dibutuhkan untuk pergi melalui semua hasil dalam setiap kasus, juga untuk menghindari memberikan evaluasi malas keuntungan yang tidak adil.)
Jon Skeet
1
Bahkan tanpa memenuhi persyaratan "hasil harus berupa array", cukup memenuhi persyaratan "hasil harus digunakan dalam beberapa fasion" akan membuat LINQ menjadi tidak optimal. Saya pikir persyaratan untuk dapat menggunakan hasilnya harus implisit!
csauve
2
@andleer: Selain yang lain, Buffer.BlockCopy hanya berfungsi dengan tipe primitif.
Jon Skeet
44
Saya mengambil contoh Matt's LINQ satu langkah lebih jauh untuk kebersihan kode:
byte[] rv = a1.Concat(a2).Concat(a3).ToArray();
Dalam kasus saya, arraynya kecil, jadi saya tidak peduli dengan kinerja.
Solusi singkat dan sederhana, tes kinerja akan luar biasa!
Sebastian
3
Ini jelas, dapat dibaca, tidak memerlukan perpustakaan / pembantu eksternal, dan, dalam hal waktu pengembangan, cukup efisien. Hebat ketika kinerja run-time tidak kritis.
binki
28
Jika Anda hanya perlu array byte baru, gunakan yang berikut ini:
Atau, jika Anda hanya perlu satu IEnumerable, pertimbangkan untuk menggunakan operator hasil C # 2.0:
IEnumerable<byte>Combine(byte[] a1,byte[] a2,byte[] a3){foreach(byte b in a1)yieldreturn b;foreach(byte b in a2)yieldreturn b;foreach(byte b in a3)yieldreturn b;}
Saya telah melakukan sesuatu yang mirip dengan opsi ke-2 Anda untuk menggabungkan aliran besar, bekerja seperti pesona. :)
Greg D
2
Pilihan kedua sangat bagus. +1.
R. Martinho Fernandes
11
Saya benar-benar mengalami beberapa masalah dengan menggunakan Concat ... (dengan array dalam 10-juta, itu benar-benar macet).
Saya menemukan berikut ini menjadi sederhana, mudah dan bekerja dengan cukup baik tanpa menabrak saya, dan berfungsi untuk jumlah array APAPUN (bukan hanya tiga) (Menggunakan LINQ):
Sebagai qwe menyatakan, saya melakukan tes dalam satu lingkaran 10.000.000 kali, dan MemoryStream keluar 290% lebih lambat dari Buffer.BlockCopy
esac
Dalam beberapa kasus, Anda mungkin melakukan iterasi lebih dari jumlah array tanpa pengetahuan sebelumnya tentang panjang array individu. Ini berfungsi dengan baik dalam skenario ini. BlockCopy bergantung pada memiliki array tujuan yang telah ditentukan sebelumnya
Sentinel
Seperti yang dikatakan @Sentinel, jawaban ini sangat cocok untuk saya karena saya tidak memiliki pengetahuan tentang ukuran hal-hal yang harus saya tulis dan memungkinkan saya melakukan hal-hal dengan sangat bersih. Itu juga bermain bagus dengan [ReadOnly] Span .NET Core 3! <byte>!
Air
Jika Anda menginisialisasi MemoryStream dengan ukuran akhir dari ukuran itu tidak akan dibuat kembali dan itu akan lebih cepat @ esac.
Sayangnya ini tidak akan bekerja dengan semua tipe. Marshal.SizeOf () tidak akan dapat mengembalikan ukuran untuk banyak jenis (coba gunakan metode ini dengan array string dan Anda akan melihat pengecualian "Ketik 'System.String' tidak dapat dikerjakan sebagai struktur yang tidak dikelola; tidak ada ukuran yang berarti atau offset dapat dihitung ". Anda dapat mencoba membatasi parameter tipe ke tipe referensi saja (dengan menambahkan where T : struct), tetapi - tidak menjadi ahli dalam jeroan CLR - saya tidak bisa mengatakan apakah Anda mungkin mendapatkan pengecualian pada struct tertentu juga (mis. jika mengandung bidang tipe referensi)
Daniel Scott
2
publicstaticbyte[]Concat(paramsbyte[][] arrays){
using (var mem =newMemoryStream(arrays.Sum(a => a.Length))){foreach(vararrayin arrays){
mem.Write(array,0,array.Length);}return mem.ToArray();}}
Jawaban Anda bisa lebih baik jika Anda telah memposting sedikit penjelasan tentang contoh kode ini.
SETELAH
1
itu menggabungkan array array byte menjadi satu array byte besar (seperti ini): [1,2,3] + [4,5] + [6,7] ==> [1,2,3,4,5 , 6,7]
Peter Ertl
1
Dapat menggunakan obat generik untuk menggabungkan array. Kode berikut dapat dengan mudah diperluas ke tiga array. Dengan cara ini Anda tidak perlu menduplikasi kode untuk berbagai jenis array. Beberapa jawaban di atas tampaknya terlalu rumit bagi saya.
BAHAYA! Metode-metode ini tidak akan bekerja dengan tipe array apa pun dengan elemen lebih dari satu byte (hampir semuanya selain array byte). Buffer.BlockCopy () bekerja dengan jumlah byte, bukan jumlah elemen array. Alasannya dapat digunakan dengan mudah dengan array byte adalah bahwa setiap elemen array adalah byte tunggal, sehingga panjang fisik array sama dengan jumlah elemen. Untuk mengubah metode byte [] John menjadi metode umum Anda harus melipatgandakan semua offset dan panjang dengan panjang byte elemen array tunggal - jika tidak, Anda tidak akan menyalin semua data.
Daniel Scott
2
Biasanya untuk membuat ini bekerja Anda akan menghitung ukuran elemen tunggal menggunakan sizeof(...)dan mengalikannya dengan jumlah elemen yang ingin Anda salin, tetapi sizeof tidak dapat digunakan dengan tipe generik. Dimungkinkan - untuk beberapa jenis - untuk digunakan Marshal.SizeOf(typeof(T)), tetapi Anda akan mendapatkan kesalahan runtime dengan tipe tertentu (mis. String). Seseorang dengan pengetahuan yang lebih menyeluruh tentang cara kerja tipe CLR akan dapat menunjukkan semua kemungkinan jebakan di sini. Cukuplah untuk mengatakan bahwa menulis metode gabungan array generik [menggunakan BlockCopy] tidak sepele.
Daniel Scott
2
Dan akhirnya - Anda dapat menulis metode penggabungan array generik seperti ini di hampir persis cara yang ditunjukkan di atas (dengan kinerja yang sedikit lebih rendah) dengan menggunakan Array.Copy sebagai gantinya. Ganti saja semua panggilan Buffer.BlockCopy dengan panggilan Array.Copy.
Terima kasih atas kontribusinya. Karena sudah ada sejumlah jawaban berperingkat tinggi untuk ini dari lebih dari satu dekade yang lalu, akan berguna untuk menawarkan penjelasan tentang apa yang membedakan pendekatan Anda. Mengapa seseorang harus menggunakan ini alih-alih misalnya jawaban yang diterima?
Jeremy Caney
Saya suka menggunakan metode yang diperluas, karena ada kode yang jelas untuk dipahami. Kode ini memilih dua larik dengan indeks mulai dan menghitung dan concat. Metode ini juga diperluas. Jadi, ini untuk semua tipe array yang siap setiap saat
Mehmet ÜNLÜ
Itu masuk akal bagi saya! Apakah Anda keberatan mengedit pertanyaan Anda untuk memasukkan informasi itu? Saya pikir akan sangat berharga bagi pembaca di masa depan untuk memiliki muka, sehingga mereka dapat dengan cepat membedakan pendekatan Anda dari jawaban yang ada. Terima kasih!
Jeremy Caney
-1
Yang Anda perlukan untuk melewati daftar Byte Arrays dan fungsi ini akan mengembalikan Anda Array Bytes (Digabung). Ini adalah solusi terbaik menurut saya :).
publicstaticbyte[]CombineMultipleByteArrays(List<byte[]> lstByteArray){
using (var ms =newMemoryStream()){
using (var doc =new iTextSharp.text.Document()){
using (var copy =newPdfSmartCopy(doc, ms)){
doc.Open();foreach(var p in lstByteArray){
using (var reader =newPdfReader(p)){
copy.AddDocument(reader);}}
doc.Close();}}return ms.ToArray();}}
Concat adalah jawaban yang tepat, tetapi karena alasan tertentu hal yang dikuasai adalah mendapatkan suara terbanyak. Jika Anda menyukai jawaban itu, mungkin Anda akan lebih menyukai solusi yang lebih umum ini:
IEnumerable<byte>Combine(paramsbyte[][] arrays){foreach(byte[] a in arrays)foreach(byte b in a)yieldreturn b;}
yang akan membiarkan Anda melakukan hal-hal seperti:
byte[] c =Combine(newbyte[]{0,1,2},newbyte[]{3,4,5}).ToArray();
Pertanyaannya secara khusus menanyakan solusi yang paling efisien . Enumerable.ToArray tidak akan menjadi sangat efisien, karena tidak dapat mengetahui ukuran array akhir untuk memulai - sedangkan teknik linting tangan bisa.
Concat
metode:IEnumerable<byte> arrays = array1.Concat(array2).Concat(array3);
Jawaban:
Untuk tipe primitif (termasuk byte), gunakan
System.Buffer.BlockCopy
sebagai gantiSystem.Array.Copy
. Lebih cepat.Saya menghitung setiap metode yang disarankan dalam satu loop yang dieksekusi 1 juta kali menggunakan 3 array masing-masing 10 byte. Inilah hasilnya:
System.Array.Copy
- 0,2187556 detikSystem.Buffer.BlockCopy
- 0,1406286 detikSaya meningkatkan ukuran setiap array menjadi 100 elemen dan menjalankan kembali tes:
System.Array.Copy
- 0,2812554 detikSystem.Buffer.BlockCopy
- 0,2500048 detikSaya meningkatkan ukuran setiap array menjadi 1000 elemen dan menjalankan kembali tes:
System.Array.Copy
- 1,0781457 detikSystem.Buffer.BlockCopy
- 1,0156445 detikAkhirnya, saya meningkatkan ukuran setiap array menjadi 1 juta elemen dan menjalankan ulang pengujian, mengeksekusi setiap loop hanya 4000 kali:
System.Array.Copy
- 13,4533833 detikSystem.Buffer.BlockCopy
- 13,1096267 detikJadi, jika Anda membutuhkan array byte baru, gunakan
Tapi, jika Anda bisa menggunakan metode
IEnumerable<byte>
, PASTI lebih suka metode LINQ Concat <>. Ini hanya sedikit lebih lambat dari operator hasil C #, tetapi lebih ringkas dan lebih elegan.Jika Anda memiliki jumlah array yang sewenang-wenang dan menggunakan .NET 3.5, Anda dapat membuat
System.Buffer.BlockCopy
solusinya lebih umum seperti ini:* Catatan: Blok di atas mengharuskan Anda menambahkan namespace berikut di bagian atas agar bisa berfungsi.
Untuk poin Jon Skeet mengenai iterasi dari struktur data berikutnya (byte array vs IEnumerable <byte>), saya menjalankan kembali tes waktu terakhir (1 juta elemen, 4000 iterasi), menambahkan loop yang mengulangi array penuh dengan masing-masing lulus:
System.Array.Copy
- 78,20550510 detikSystem.Buffer.BlockCopy
- 77,89261900 detikIntinya adalah, SANGAT penting untuk memahami efisiensi penciptaan dan penggunaan struktur data yang dihasilkan. Dengan hanya berfokus pada efisiensi penciptaan dapat mengabaikan inefisiensi yang terkait dengan penggunaan. Salam, Jon.
sumber
Banyak jawaban bagi saya tampaknya mengabaikan persyaratan yang dinyatakan:
Keduanya bersama-sama mengesampingkan urutan byte LINQ - apa pun dengan
yield
akan membuat tidak mungkin untuk mendapatkan ukuran akhir tanpa iterasi melalui seluruh urutan.Jika itu bukan persyaratan nyata tentunya, LINQ bisa menjadi solusi yang sangat baik (atau
IList<T>
implementasinya). Namun, saya akan berasumsi bahwa Superdumbell tahu apa yang dia inginkan.(EDIT: Saya baru saja berpikir lain. Ada perbedaan besar antara membuat salinan array dan membacanya dengan malas. Pertimbangkan apa yang terjadi jika Anda mengubah data di salah satu array "sumber" setelah memanggil
Combine
(atau apa pun) ) tetapi sebelum menggunakan hasilnya - dengan evaluasi malas, perubahan itu akan terlihat. Dengan salinan langsung, itu tidak akan. Situasi yang berbeda akan memerlukan perilaku yang berbeda - hanya sesuatu yang harus diperhatikan.)Berikut adalah metode yang saya usulkan - yang sangat mirip dengan yang terkandung dalam beberapa jawaban lain, tentu saja :)
Tentu saja versi "params" membutuhkan pembuatan array array byte terlebih dahulu, yang memperkenalkan inefisiensi tambahan.
sumber
Saya mengambil contoh Matt's LINQ satu langkah lebih jauh untuk kebersihan kode:
Dalam kasus saya, arraynya kecil, jadi saya tidak peduli dengan kinerja.
sumber
Jika Anda hanya perlu array byte baru, gunakan yang berikut ini:
Atau, jika Anda hanya perlu satu IEnumerable, pertimbangkan untuk menggunakan operator hasil C # 2.0:
sumber
Saya benar-benar mengalami beberapa masalah dengan menggunakan Concat ... (dengan array dalam 10-juta, itu benar-benar macet).
Saya menemukan berikut ini menjadi sederhana, mudah dan bekerja dengan cukup baik tanpa menabrak saya, dan berfungsi untuk jumlah array APAPUN (bukan hanya tiga) (Menggunakan LINQ):
sumber
Kelas memorystream melakukan pekerjaan ini dengan cukup baik untuk saya. Saya tidak bisa menjalankan kelas buffer secepat memorystream.
sumber
sumber
where T : struct
), tetapi - tidak menjadi ahli dalam jeroan CLR - saya tidak bisa mengatakan apakah Anda mungkin mendapatkan pengecualian pada struct tertentu juga (mis. jika mengandung bidang tipe referensi)sumber
Dapat menggunakan obat generik untuk menggabungkan array. Kode berikut dapat dengan mudah diperluas ke tiga array. Dengan cara ini Anda tidak perlu menduplikasi kode untuk berbagai jenis array. Beberapa jawaban di atas tampaknya terlalu rumit bagi saya.
sumber
Inilah generalisasi jawaban yang diberikan oleh @Jon Skeet. Pada dasarnya sama, hanya dapat digunakan untuk semua jenis array, tidak hanya byte:
sumber
sizeof(...)
dan mengalikannya dengan jumlah elemen yang ingin Anda salin, tetapi sizeof tidak dapat digunakan dengan tipe generik. Dimungkinkan - untuk beberapa jenis - untuk digunakanMarshal.SizeOf(typeof(T))
, tetapi Anda akan mendapatkan kesalahan runtime dengan tipe tertentu (mis. String). Seseorang dengan pengetahuan yang lebih menyeluruh tentang cara kerja tipe CLR akan dapat menunjukkan semua kemungkinan jebakan di sini. Cukuplah untuk mengatakan bahwa menulis metode gabungan array generik [menggunakan BlockCopy] tidak sepele.sumber
Yang Anda perlukan untuk melewati daftar Byte Arrays dan fungsi ini akan mengembalikan Anda Array Bytes (Digabung). Ini adalah solusi terbaik menurut saya :).
sumber
Concat adalah jawaban yang tepat, tetapi karena alasan tertentu hal yang dikuasai adalah mendapatkan suara terbanyak. Jika Anda menyukai jawaban itu, mungkin Anda akan lebih menyukai solusi yang lebih umum ini:
yang akan membiarkan Anda melakukan hal-hal seperti:
sumber