Comment faites-vous? Étant donné un tableau d'octets:
byte[] foo = new byte[4096];
Comment puis-je obtenir les premiers x octets du tableau en tant que tableau séparé? (Plus précisément, j'en ai besoin en tant que IEnumerable<byte>
)
C'est pour travailler avec l' Socket
art. Je pense que le moyen le plus simple serait le découpage de tableaux, similaire à la syntaxe Perls:
@bar = @foo[0..40];
Ce qui retournerait les 41 premiers éléments dans le @bar
tableau. Y a-t-il quelque chose en C # qui me manque, ou y a-t-il autre chose que je devrais faire?
LINQ est une option pour moi (.NET 3.5), si cela aide.
Réponses:
Les tableaux sont énumérables, donc votre
foo
déjà est unIEnumerable<byte>
soi. Utilisez simplement les méthodes de séquence LINQ commeTake()
pour en obtenir ce que vous voulez (n'oubliez pas d'inclure l'Linq
espace de noms avecusing System.Linq;
):Si vous avez vraiment besoin d'un tableau de n'importe quelle
IEnumerable<byte>
valeur, vous pouvez utiliser laToArray()
méthode pour cela. Cela ne semble pas être le cas ici.la source
[2,3] => [1,1], [1,2], [1,3], [2,1], [2,2], [2,3]
. Les tableaux irréguliers sont également énumérables, mais au lieu de renvoyer une valeur lorsqu'ils sont énumérés, ils retournent leur tableau interne. Comme ça:type[][] jaggedArray; foreach (type[] innerArray in jaggedArray) { }
IEnumerable<T>
", alors ma déclaration aurait été plus claire. Voir aussi ceci: stackoverflow.com/questions/721882/…Vous pourriez utiliser
ArraySegment<T>
. Il est très léger car il ne copie pas le tableau:la source
Vous pouvez utiliser la
CopyTo()
méthode des tableaux .Ou avec LINQ, vous pouvez utiliser
Skip()
etTake()
...la source
Skip()
. VousTake()
n'obtiendrez tout simplement pas une tranche arbitraire. De plus, je cherchais quand même une solution LINQ (tranche IEnumerable, mais je savais que les résultats sur les tableaux seraient plus faciles à trouver).//
la source
À partir de C # 8.0 / .Net Core 3.0
Le découpage des tableaux sera pris en charge, ainsi que les nouveaux types
Index
et enRange
cours d'ajout.Gamme Struct docs
Index Struct docs
Exemple de code ci-dessus tiré du blog C # 8.0 .
notez que le
^
préfixe indique le comptage à partir de la fin du tableau. Comme illustré dans l' exemple de documentsRange
etIndex
également travailler en dehors des tableaux de découpage, par exemple avec des bouclesParcourra les entrées 1 à 4
notez qu'au moment de la rédaction de cette réponse, C # 8.0 n'est pas encore officiellement publié.C # 8.x et .Net Core 3.x sont désormais disponibles dans Visual Studio 2019 et versions ultérieures
la source
En C # 7.2 , vous pouvez utiliser
Span<T>
. L'avantage du nouveauSystem.Memory
système est qu'il n'a pas besoin de copier autour des données.La méthode dont vous avez besoin est la suivante
Slice
:De nombreuses méthodes prennent désormais en charge
Span
etIReadOnlySpan
, il sera donc très simple d'utiliser ce nouveau type.Notez qu'au moment de l'écriture, le
Span<T>
type n'est pas encore défini dans la version la plus récente de .NET (4.7.1), donc pour l'utiliser, vous devez installer le package System.Memory de NuGet.la source
Span<T>
type n'est pas encore défini dans la version la plus récente de .Net (4.7.1), donc pour l'utiliser, vous devez installer leSystem.Memory
depuis NuGet (et n'oubliez pas de cocher "inclure la pré-version" lorsque vous le recherchez dans NuGet)Une autre possibilité que je n'ai pas vue mentionnée ici: Buffer.BlockCopy () est légèrement plus rapide que Array.Copy (), et il a l'avantage supplémentaire de pouvoir convertir à la volée à partir d'un tableau de primitives (disons, court []) à un tableau d'octets, ce qui peut être pratique lorsque vous avez des tableaux numériques que vous devez transmettre via Sockets.
la source
Buffer.BlockCopy
produit des résultats différents queArray.Copy()
même s'ils acceptent les mêmes paramètres - il y avait beaucoup d'éléments vides. Pourquoi?Array.Copy(array1, 0, array2, 0, 10)
, maisBuffer.BlockCopy(array1, 0, array2, 0, 10 * sizeof(int))
.Si vous voulez
IEnumerable<byte>
, alors justela source
Voici une méthode d'extension simple qui renvoie une tranche en tant que nouveau tableau:
Ensuite, vous pouvez l'utiliser comme:
la source
Si vous ne voulez pas ajouter LINQ ou d'autres extensions, faites simplement:
la source
Error CS0246: The type or namespace name 'List<>' could not be found (are you missing a using directive or an assembly reference?)
La documentation de Microsoft est sans espoir avec des centaines d'entrées "Liste" indexées. Quelle est la bonne ici?System.Collections.Generic.List
Vous pouvez utiliser un wrapper autour du tableau d'origine (qui est IList), comme dans ce morceau de code (non testé).
}
la source
Array.Copy
, même si cela peut avoir de nombreux avantages, comme la SubList étant littéralement une région de la liste parent, au lieu d'une copie des entrées de la liste.la source
Pour les tableaux d'octets, System.Buffer.BlockCopy vous donnera les meilleures performances.
la source
Vous pouvez utiliser la méthode d'extension Take
la source
Cela peut être une solution qui:
Le résultat est alors un IEnumerable <IEnumerable <byte >> avec un premier IEnumerable <byte> contient les 40 premiers octets de foo , et un second IEnumerable <byte> contient le reste.
J'ai écrit une classe wrapper, toute l'itération est paresseuse, j'espère que cela pourrait aider:
la source
Je ne pense pas que C # supporte la sémantique Range. Vous pouvez cependant écrire une méthode d'extension, comme:
Mais comme d'autres l'ont dit, si vous n'avez pas besoin de définir un index de démarrage,
Take
c'est tout ce dont vous avez besoin.la source
Voici une fonction d'extension qui utilise un générique et se comporte comme la fonction PHP array_slice . Un décalage et une longueur négatifs sont autorisés.
la source
start
n'est pas compris entre 0 etarr.Length
, il devrait probablement lever une exception hors limites. De plus,end >= start >= 0
pour que vous n'ayez pas besoin de vérifierend < 0
, il n'est pas possible que cela se produise. Vous pourriez probablement le faire encore plus succinctement en vérifiant celalength >= 0
, puislen = Math.min(length, arr.Length - start)
au lieu de vous en occuperend
.la source