Wie machst du das? Gegeben ein Byte-Array:
byte[] foo = new byte[4096];
Wie würde ich die ersten x Bytes des Arrays als separates Array erhalten? (Speziell brauche ich es als IEnumerable<byte>
)
Dies ist für die Arbeit mit Socket
s. Ich denke, der einfachste Weg wäre das Schneiden von Arrays, ähnlich der Perls-Syntax:
@bar = @foo[0..40];
Welches würde die ersten 41 Elemente in das @bar
Array zurückgeben. Gibt es etwas in C #, das mir gerade fehlt, oder gibt es noch etwas, was ich tun sollte?
LINQ ist eine Option für mich (.NET 3.5), falls dies hilfreich ist.
Antworten:
Arrays sind aufzählbar, so dass Sie
foo
bereits ein Selbst sindIEnumerable<byte>
. Verwenden Sie einfach LINQ-SequenzmethodenTake()
, um das zu erreichen, was Sie wollen (vergessen Sie nicht, denLinq
Namespace mit einzuschließenusing System.Linq;
):Wenn Sie wirklich ein Array von einem beliebigen
IEnumerable<byte>
Wert benötigen , können Sie dieToArray()
Methode dafür verwenden. Dies scheint hier nicht der Fall zu sein.quelle
[2,3] => [1,1], [1,2], [1,3], [2,1], [2,2], [2,3]
. Gezackte Arrays sind ebenfalls aufzählbar, aber anstatt bei der Aufzählung einen Wert zurückzugeben, geben sie ihr inneres Array zurück. So:type[][] jaggedArray; foreach (type[] innerArray in jaggedArray) { }
IEnumerable<T>
", dann wäre meine Aussage klarer gewesen. Siehe auch dies: stackoverflow.com/questions/721882/…Sie könnten verwenden
ArraySegment<T>
. Es ist sehr leicht, da es das Array nicht kopiert:quelle
Sie können die Arrays-
CopyTo()
Methode verwenden.Oder mit LINQ können Sie verwenden
Skip()
undTake()
...quelle
Skip()
. Sie bekommen einfachTake()
keine willkürliche Scheibe. Außerdem suchte ich sowieso nach einer LINQ-Lösung (Slice IEnumerable, aber ich wusste, dass Ergebnisse über Arrays leichter zu finden sind).// //
quelle
Ab C # 8.0 / .Net Core 3.0
Array-Slicing wird zusammen mit den neuen Typen unterstützt
Index
undRange
hinzugefügt.Range Struct-Dokumente
Index Struct-Dokumente
Das obige Codebeispiel stammt aus dem C # 8.0- Blog .
Beachten Sie, dass das
^
Präfix das Zählen ab dem Ende des Arrays anzeigt . Wie im Dokumentbeispiel gezeigtRange
undIndex
arbeiten auch außerhalb von Slicing-Arrays, beispielsweise mit SchleifenDurchläuft die Einträge 1 bis 4
Beachten Sie, dass C # 8.0 zum Zeitpunkt des Schreibens dieser Antwort noch nicht offiziell freigegeben ist.C # 8.x und .Net Core 3.x sind jetzt in Visual Studio 2019 und höher verfügbar
quelle
In C # 7.2 können Sie verwenden
Span<T>
. Der Vorteil des neuenSystem.Memory
Systems besteht darin, dass keine Daten kopiert werden müssen.Die Methode, die Sie benötigen, ist
Slice
:Viele Methoden unterstützen jetzt
Span
undIReadOnlySpan
daher wird es sehr einfach sein, diesen neuen Typ zu verwenden.Beachten Sie, dass der
Span<T>
Typ zum Zeitpunkt des Schreibens noch nicht in der neuesten Version von .NET (4.7.1) definiert ist. Um ihn zu verwenden, müssen Sie das System.Memory-Paket von NuGet installieren .quelle
Span<T>
Art nicht in der der neuesten Version von .Net noch (4.7.1) , so dass es zu verwenden , definiert ist müssen Sie die InstallationSystem.Memory
von NuGet (und denken Sie daran, tick „schließen Prerelease“ , wenn es in NuGet Suche)Eine andere Möglichkeit, die ich hier nicht gesehen habe: Buffer.BlockCopy () ist etwas schneller als Array.Copy () und hat den zusätzlichen Vorteil, dass es in der Lage ist, on-the-fly aus einem Array von Grundelementen (z. B. kurz) zu konvertieren []) zu einem Array von Bytes, was nützlich sein kann, wenn Sie numerische Arrays haben, die Sie über Sockets übertragen müssen.
quelle
Buffer.BlockCopy
führten zu anderen Ergebnissen alsArray.Copy()
obwohl sie die gleichen Parameter akzeptieren - es gab viele leere Elemente. Warum?Array.Copy(array1, 0, array2, 0, 10)
, würden Sie aber verwendenBuffer.BlockCopy(array1, 0, array2, 0, 10 * sizeof(int))
.Wenn du willst
IEnumerable<byte>
, dann einfachquelle
Hier ist eine einfache Erweiterungsmethode, die ein Slice als neues Array zurückgibt:
Dann können Sie es verwenden als:
quelle
Wenn Sie LINQ oder andere Erweiterungen nicht hinzufügen möchten, gehen Sie einfach wie folgt vor :
quelle
Error CS0246: The type or namespace name 'List<>' could not be found (are you missing a using directive or an assembly reference?)
Die Microsoft-Dokumentation ist hoffnungslos, da Hunderte von "Listen" -Einträgen indiziert sind. Was ist hier das Richtige?System.Collections.Generic.List
Sie können einen Wrapper um das ursprüngliche Array (IList) verwenden, wie in diesem (nicht getesteten) Code.
}}
quelle
Array.Copy
, obwohl dies viele Vorteile haben kann, z. B. dass die Unterliste buchstäblich eine Region innerhalb der übergeordneten Liste ist, anstatt eine Kopie der Einträge in der Liste.quelle
Für Byte-Arrays bietet System.Buffer.BlockCopy die beste Leistung.
quelle
Sie können die Take-Erweiterungsmethode verwenden
quelle
Dies kann eine Lösung sein, die:
Das Ergebnis ist dann, dass ein IEnumerable <IEnumerable <Byte >> mit einem ersten IEnumerable <Byte> die ersten 40 Bytes von foo enthält und ein zweites IEnumerable <Byte> den Rest enthält.
Ich habe eine Wrapper-Klasse geschrieben, die ganze Iteration ist faul, hoffe es könnte helfen:
quelle
Ich glaube nicht, dass C # die Range-Semantik unterstützt. Sie könnten jedoch eine Erweiterungsmethode schreiben, wie:
Aber wie andere gesagt haben, wenn Sie keinen Startindex festlegen müssen,
Take
ist alles, was Sie brauchen.quelle
Hier ist eine Erweiterungsfunktion, die eine generische Funktion verwendet und sich wie die PHP-Funktion array_slice verhält . Negativer Versatz und Länge sind zulässig.
quelle
start
es nicht zwischen 0 und liegtarr.Length
, sollte es wahrscheinlich eine Ausnahme außerhalb der Grenzen auslösen. Auchend >= start >= 0
, so dass Sie nicht brauchen zu überprüfenend < 0
, ist es nicht möglich , dass es passieren wird. Sie könnten es wahrscheinlich noch prägnanter machen, indem Sie das überprüfenlength >= 0
und dann,len = Math.min(length, arr.Length - start)
anstatt damit herumzuspielenend
.quelle