Jak ty to robisz? Biorąc pod uwagę tablicę bajtów:
byte[] foo = new byte[4096];
Jak uzyskać pierwsze x bajtów tablicy jako osobną tablicę? (W szczególności potrzebuję go jako IEnumerable<byte>
)
To jest do pracy z Socket
s. Myślę, że najłatwiejszym sposobem byłoby dzielenie tablic, podobne do składni Perlsa:
@bar = @foo[0..40];
Co zwróci pierwsze 41 elementów do @bar
tablicy. Czy jest coś w C #, którego po prostu brakuje, czy jest coś innego, co powinienem zrobić?
LINQ jest dla mnie opcją (.NET 3.5), jeśli to pomaga.
Odpowiedzi:
Tablice są policzalne, więc
foo
już jesteśIEnumerable<byte>
sobą. Po prostu użyj metod sekwencji LINQ, takich jak,Take()
aby uzyskać z niej to, czego chcesz (nie zapomnij dołączyćLinq
przestrzeni nazwusing System.Linq;
):Jeśli naprawdę potrzebujesz tablicy z dowolnej
IEnumerable<byte>
wartości, możesz użyć do tegoToArray()
metody. Wydaje się, że tak nie jest.źródło
[2,3] => [1,1], [1,2], [1,3], [2,1], [2,2], [2,3]
. Poszarpane tablice są również wyliczalne, ale zamiast zwracać wartość po wyliczeniu, zwracają swoją wewnętrzną tablicę. W ten sposób:type[][] jaggedArray; foreach (type[] innerArray in jaggedArray) { }
IEnumerable<T>
”, wtedy moje oświadczenie byłoby jaśniejsze. Zobacz także: stackoverflow.com/questions/721882/...Możesz użyć
ArraySegment<T>
. Jest bardzo lekki, ponieważ nie kopiuje tablicy:źródło
Możesz użyć
CopyTo()
metody tablic .Lub z LINQ możesz używać
Skip()
iTake()
...źródło
Skip()
. Po prostuTake()
nie dostanę cię w dowolny kawałek. Poza tym i tak szukałem rozwiązania LINQ (kawałek IEnumerable, ale wiedziałem, że wyniki dotyczące tablicy będą łatwiejsze do znalezienia).//
źródło
Począwszy od C # 8.0 / .Net Core 3.0
Krojenie tablic będzie obsługiwane, wraz z nowymi typami
Index
iRange
dodawanymi.Zakres Dokumenty Struct
Indeks Dokumenty Struct
Powyższy przykładowy kod pochodzi z bloga C # 8.0 .
zwróć uwagę, że
^
przedrostek wskazuje zliczanie od końca tablicy. Jak pokazano w przykładzie dokumentacjiRange
aIndex
także pracować poza tablicami krojenia, na przykład z pętlamiPrzechodzi przez wpisy od 1 do 4
zwróć uwagę, że w chwili pisania tej odpowiedzi wersja C # 8.0 nie została jeszcze oficjalnie wydana w wersjiC # 8.x, a program .Net Core 3.x jest już dostępny w programie Visual Studio 2019 i nowszych wersjach
źródło
W C # 7.2 możesz użyć
Span<T>
. Zaletą nowegoSystem.Memory
systemu jest to, że nie wymaga kopiowania wokół danych.Potrzebna metoda to
Slice
:Wiele metod obsługują teraz
Span
iIReadOnlySpan
tak będzie to bardzo proste do korzystania z tego nowego typu.Zauważ, że w chwili pisania tego
Span<T>
typu typ nie jest jeszcze zdefiniowany w najnowszej wersji .NET (4.7.1), więc aby go użyć, musisz zainstalować pakiet System.Memory z NuGet.źródło
Span<T>
typ nie jest jeszcze zdefiniowany w najnowszej wersji .Net (4.7.1), więc aby go użyć, musisz zainstalować goSystem.Memory
z NuGet (i pamiętaj, aby zaznaczyć „włącz prerelease” podczas wyszukiwania go w NuGet)Inna możliwość, o której nie wspomniałem tutaj: Buffer.BlockCopy () jest nieco szybszy niż Array.Copy () i ma tę dodatkową zaletę, że jest w stanie konwertować w locie z szeregu prymitywów (np. []) do tablicy bajtów, co może być przydatne, gdy masz tablice numeryczne, które musisz przesyłać przez gniazda.
źródło
Buffer.BlockCopy
dało inne wyniki niżArray.Copy()
te, które akceptują te same parametry - było wiele pustych elementów. Czemu?Array.Copy(array1, 0, array2, 0, 10)
, aleBuffer.BlockCopy(array1, 0, array2, 0, 10 * sizeof(int))
.Jeśli chcesz
IEnumerable<byte>
, to tylkoźródło
Oto prosta metoda rozszerzenia, która zwraca wycinek jako nową tablicę:
Następnie możesz użyć go jako:
źródło
Jeśli nie chcesz dodawać LINQ lub innych rozszerzeń, po prostu wykonaj:
źródło
Error CS0246: The type or namespace name 'List<>' could not be found (are you missing a using directive or an assembly reference?)
Dokumentacja Microsoft jest beznadziejna, z indeksowanymi setkami pozycji „List”. Który tutaj jest właściwy?System.Collections.Generic.List
Możesz użyć opakowania wokół oryginalnej tablicy (która jest IList), tak jak w tym (nieprzetestowanym) fragmencie kodu.
}
źródło
Array.Copy
, chociaż może to mieć wiele zalet, takich jak SubList dosłownie będący regionem na liście nadrzędnej, zamiast kopii wpisów na liście.źródło
W przypadku tablic bajtowych System.Buffer.BlockCopy zapewnia najlepszą wydajność.
źródło
Możesz użyć opcji Weź rozszerzenie
źródło
Może to być rozwiązanie, które:
Następnie wynikiem jest IEnumerable <IEnumerable <bajt >> z pierwszym IEnumerable <bajt> zawiera pierwsze 40 bajtów foo , a drugi IEnumerable <bajt> zawiera resztę.
Napisałem klasę otoki, cała iteracja jest leniwa, mam nadzieję, że może pomóc:
źródło
Nie sądzę, aby C # obsługuje semantykę zakresu. Możesz jednak napisać metodę rozszerzenia, na przykład:
Ale jak powiedzieli inni, jeśli nie trzeba ustawiać indeksu początkowego
Take
, wystarczy.źródło
Oto funkcja rozszerzenia, która używa funkcji ogólnej i zachowuje się jak funkcja PHP array_slice . Dozwolone jest przesunięcie ujemne i długość.
źródło
start
nie mieści się w przedziale od 0 doarr.Length
, prawdopodobnie powinien wyrzucić wyjątek poza granice. Ponadto,end >= start >= 0
więc nie trzeba sprawdzaćend < 0
, nie jest możliwe, aby tak się stało. Prawdopodobnie możesz to zrobić jeszcze bardziej zwięźle, sprawdzając to,length >= 0
a następnielen = Math.min(length, arr.Length - start)
zamiast marudzićend
.źródło