306 votes

Tranches de tableaux en C#

Comment faites-vous ? Étant donné un tableau d'octets :

byte[] foo = new byte[4096];

Comment puis-je obtenir les x premiers octets du tableau comme un tableau séparé ? (Plus précisément, j'en ai besoin comme un IEnumerable<byte> )

Il s'agit de travailler avec Socket s. Je pense que le moyen le plus simple serait le découpage en tableaux, similaire à la syntaxe de Perls :

@bar = @foo[0..40];

Ce qui renverrait les 41 premiers éléments dans le @bar tableau. Y a-t-il quelque chose en C# qui m'échappe, ou y a-t-il autre chose que je devrais faire ?

LINQ est une option pour moi (.NET 3.5), si cela peut aider.

3 votes

Le découpage en tableaux est une proposition pour c# 7.2 github.com/dotnet/csharplang/issues/185

5 votes

C# 8.0 verra l'introduction du découpage en tableaux natif. Voir la réponse pour plus de détails

2 votes

Vous pourriez être intéressé par ArraySlice<T> qui implémente le découpage en tranches de tableaux avec une étape comme vue sur les données originales : github.com/henon/SliceAndDice

248voto

Mike Scott Points 6062

Vous pourriez utiliser ArraySegment<T> . Il est très léger car il ne copie pas le tableau :

string[] a = { "one", "two", "three", "four", "five" };
var segment = new ArraySegment<string>( a, 1, 2 );

5 votes

Malheureusement, ce n'est pas IEnumerable.

1 votes

C'est vrai, mais il serait facile d'écrire une enveloppe d'itérateur qui implémente IEnumerable.

29 votes

Quelqu'un sait-il pourquoi ce n'est pas IEnumerable ? Je ne le sais pas. Il semble qu'il devrait l'être.

240voto

peSHIr Points 3911

Les tableaux sont énumérables, donc votre foo est déjà un IEnumerable<byte> lui-même. Il suffit d'utiliser des méthodes de séquence LINQ comme Take() pour obtenir ce que vous voulez (n'oubliez pas d'inclure l'élément Linq avec using System.Linq; ) :

byte[] foo = new byte[4096];

var bar = foo.Take(41);

Si vous avez vraiment besoin d'un tableau de n'importe quel IEnumerable<byte> vous pouvez utiliser l'option ToArray() pour cela. Cela ne semble pas être le cas ici.

5 votes

Si nous voulons copier dans un autre tableau, il suffit d'utiliser la méthode statique Array.Copy. Cependant, je pense que les autres réponses ont interprété l'intention correctement, un autre tableau n'est pas nécessaire, juste un IEnumberable<byte> qui couvre les 41 premiers octets.

2 votes

Notez que seuls les tableaux unidimensionnels et en dents de scie sont énumérables, les tableaux multidimensionnels ne le sont pas.

15 votes

Notez que l'utilisation de Array.Copy est beaucoup plus rapide que l'utilisation des méthodes Take ou Skip de LINQ.

168voto

Arjan Einbu Points 7941

Vous pourriez utiliser les tableaux CopyTo() méthode.

Ou avec LINQ, vous pouvez utiliser Skip() et Take() ...

byte[] arr = {1, 2, 3, 4, 5, 6, 7, 8};
var subset = arr.Skip(2).Take(2);

1 votes

+1 pour une bonne idée, mais je dois utiliser le tableau retourné comme entrée pour une autre fonction, ce qui fait que CopyTo nécessite une variable temporaire. Je vais encore attendre d'autres réponses.

5 votes

Je ne suis pas encore familier avec LINQ, peut-être est-ce une preuve supplémentaire que je devrais vraiment l'être.

15 votes

cette approche est au moins 50x plus lente que Array.Copy. Ce n'est pas un problème dans de nombreuses situations, mais lorsque vous effectuez un découpage de tableau dans un cycle, la baisse de performance est très évidente.

59voto

WOPR Points 2374
static byte[] SliceMe(byte[] source, int length)
{
    byte[] destfoo = new byte[length];
    Array.Copy(source, 0, destfoo, 0, length);
    return destfoo;
}

//

var myslice = SliceMe(sourcearray,41);

13 votes

Je pense que Buffer.BlockCopy() est plus efficace et permet d'obtenir les mêmes résultats.

15voto

Marc Gravell Points 482669

Si vous voulez IEnumerable<byte> alors juste

IEnumerable<byte> data = foo.Take(x);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X