Bagaimana Anda melakukannya? Diberikan array byte:
byte[] foo = new byte[4096];
Bagaimana saya mendapatkan x byte pertama dari array sebagai array terpisah? (Secara khusus, saya membutuhkannya sebagai IEnumerable<byte>
)
Ini untuk bekerja dengan Socket
s. Saya pikir cara termudah adalah mengiris array, mirip dengan sintaks Perls:
@bar = @foo[0..40];
Yang akan mengembalikan 41 elemen pertama ke dalam @bar
array. Apakah ada sesuatu di C # yang saya lewatkan, atau ada hal lain yang harus saya lakukan?
LINQ adalah opsi untuk saya (.NET 3.5), jika itu membantu.
Jawaban:
Array dapat dihitung, sehingga Anda
foo
sudah merupakanIEnumerable<byte>
dirinya sendiri. Cukup gunakan metode urutan LINQTake()
untuk mendapatkan apa yang Anda inginkan (jangan lupa menyertakanLinq
namespaceusing System.Linq;
):Jika Anda benar-benar membutuhkan array dari
IEnumerable<byte>
nilai apa pun , Anda bisa menggunakanToArray()
metode untuk itu. Tampaknya tidak demikian di sini.sumber
[2,3] => [1,1], [1,2], [1,3], [2,1], [2,2], [2,3]
. Array bergerigi juga enumerable tetapi bukannya mengembalikan nilai ketika disebutkan, mereka mengembalikan array batin mereka. Seperti ini:type[][] jaggedArray; foreach (type[] innerArray in jaggedArray) { }
IEnumerable<T>
", maka pernyataan saya akan menjadi lebih jelas. Lihat juga ini: stackoverflow.com/questions/721882/…Anda bisa menggunakannya
ArraySegment<T>
. Ini sangat ringan karena tidak menyalin array:sumber
Anda bisa menggunakan array
CopyTo()
metode .Atau dengan LINQ yang dapat Anda gunakan
Skip()
danTake()
...sumber
Skip()
. HanyaTake()
tidak akan membuat Anda mendapatkan potongan acak. Selain itu, saya masih mencari solusi LINQ (iris IEnumerable, tapi saya tahu hasil tentang array akan lebih mudah ditemukan).//
sumber
Mulai dari C # 8.0 / .Net Core 3.0
Mengiris array akan didukung, bersama dengan tipe baru
Index
danRange
ditambahkan.Range Struct docs
Indeks Struct docs
Sampel kode di atas diambil dari blog C # 8.0 .
perhatikan bahwa
^
awalan menunjukkan penghitungan dari akhir array. Seperti yang ditunjukkan pada contoh dokumenRange
danIndex
juga bekerja di luar array slicing, misalnya dengan loopAkan mengulangi entri 1 hingga 4
perhatikan bahwa pada saat penulisan jawaban ini, C # 8.0 belum secara resmi dirilisC # 8.x dan .Net Core 3.x sekarang tersedia di Visual Studio 2019 dan seterusnya
sumber
Di C # 7.2 , Anda dapat menggunakan
Span<T>
. Manfaat dariSystem.Memory
sistem baru ini adalah tidak perlu menyalin data.Metode yang Anda butuhkan adalah
Slice
:Banyak metode sekarang mendukung
Span
danIReadOnlySpan
, jadi akan sangat mudah untuk menggunakan tipe baru ini.Perhatikan bahwa pada saat penulisan,
Span<T>
tipe ini belum didefinisikan dalam versi .NET terbaru (4.7.1) sehingga untuk menggunakannya Anda perlu menginstal paket System.Memory dari NuGet.sumber
Span<T>
jenis ini belum didefinisikan dalam versi .Net terbaru (4.7.1) sehingga untuk menggunakannya Anda harus menginstalSystem.Memory
dari NuGet (dan ingat untuk mencentang "sertakan prerelease" saat mencarinya di NuGet)Kemungkinan lain yang belum saya lihat disebutkan di sini: Buffer.BlockCopy () sedikit lebih cepat daripada Array.Copy (), dan memiliki manfaat tambahan untuk dapat mengkonversi on-the-fly dari berbagai primitif (katakanlah, pendek []) ke array byte, yang bisa berguna ketika Anda memiliki array numerik yang perlu Anda transmisikan melalui Soket.
sumber
Buffer.BlockCopy
menghasilkan hasil yang berbeda daripadaArray.Copy()
meskipun mereka menerima parameter yang sama - ada banyak elemen kosong. Mengapa?Array.Copy(array1, 0, array2, 0, 10)
, tetapiBuffer.BlockCopy(array1, 0, array2, 0, 10 * sizeof(int))
.Jika Anda mau
IEnumerable<byte>
, maka adilsumber
Berikut adalah metode ekstensi sederhana yang mengembalikan sepotong sebagai array baru:
Maka Anda dapat menggunakannya sebagai:
sumber
Jika Anda tidak ingin menambahkan LINQ atau ekstensi lain, cukup lakukan:
sumber
Error CS0246: The type or namespace name 'List<>' could not be found (are you missing a using directive or an assembly reference?)
Dokumentasi Microsoft tidak ada harapan dengan ratusan entri "Daftar" diindeks. Apa yang benar di sini?System.Collections.Generic.List
Anda bisa menggunakan pembungkus di sekitar array asli (yang adalah IList), seperti dalam potongan kode (belum teruji) ini.
}
sumber
Array.Copy
, meskipun ini dapat memiliki banyak keuntungan, seperti SubList yang secara harfiah menjadi wilayah di dalam Daftar induk, daripada salinan entri dalam Daftar.sumber
Untuk byte array System.Buffer.BlockCopy akan memberikan Anda kinerja terbaik.
sumber
Anda dapat menggunakan Ambil metode ekstensi
sumber
Ini mungkin solusi yang:
Maka hasilnya adalah IEnumerable <IEnumerable <byte >> dengan IEnumerable <byte> pertama berisi 40 byte pertama dari foo , dan IEnumerable kedua <byte> memegang sisanya.
Saya menulis kelas pembungkus, seluruh iterasi malas, berharap bisa membantu:
sumber
Saya tidak berpikir C # mendukung semantik Range. Anda dapat menulis metode ekstensi, seperti:
Tetapi seperti yang dikatakan orang lain jika Anda tidak perlu menetapkan indeks awal, itulah
Take
yang Anda butuhkan.sumber
Berikut ini adalah fungsi ekstensi yang menggunakan generik dan berperilaku seperti fungsi PHP array_slice . Offset dan panjang negatif diizinkan.
sumber
start
tidak antara 0 danarr.Length
, mungkin harus membuang pengecualian di luar batas. Juga,end >= start >= 0
jadi Anda tidak perlu memeriksaend < 0
, itu tidak mungkin terjadi. Anda mungkin bisa melakukannya dengan lebih ringkas dengan memeriksa itulength >= 0
dan kemudianlen = Math.min(length, arr.Length - start)
alih-alih berkutat denganend
.sumber