web-dev-qa-db-fra.com

Tableau tranches en C #

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

byte[] foo = new byte[4096];

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

Ceci est pour travailler avec Sockets. Je pense que le moyen le plus simple serait le découpage en tableau, similaire à la syntaxe Perls:

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

Ce qui renverrait les 41 premiers éléments dans le tableau @bar. Y-a-t-il quelque chose dans 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 peut vous aider.

205
Matthew Scharley

Les tableaux étant énumérables, votre foo est déjà un IEnumerable<byte> lui-même. Utilisez simplement les méthodes de séquence LINQ telles que Take() pour obtenir ce que vous voulez en sortir (n'oubliez pas d'inclure l'espace de noms Linq avec using System.Linq;):

byte[] foo = new byte[4096];

var bar = foo.Take(41);

Si vous avez réellement besoin d'un tableau à partir de n'importe quelle valeur IEnumerable<byte>, vous pouvez utiliser la méthode ToArray() pour cela. Cela ne semble pas être le cas ici.

181
peSHIr

Vous pouvez 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 );
_
196
Mike Scott

Vous pouvez utiliser la méthode arrays CopyTo().

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);
122
Arjan Einbu
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);
51
WOPR

Une autre possibilité que je n’ai pas vue mentionnée ici: Buffer.BlockCopy () est légèrement plus rapide que Array.Copy () et présente l’avantage supplémentaire de pouvoir convertir à la volée à partir d’un tableau de primitives (disons []) en un tableau d'octets, ce qui peut être pratique lorsque vous devez transmettre des tableaux numériques sur Sockets.

16
Ken Smith

Dans C # 7.2 , vous pouvez utiliser Span<T> . L'avantage du nouveau système System.Memory est qu'il n'a pas besoin de copier les données.

La méthode dont vous avez besoin est Slice:

_Span<byte> slice = foo.Slice(0, 40);
_

Beaucoup de méthodes supportent maintenant Span et IReadOnlySpan, il sera donc très simple d'utiliser ce nouveau type.

Notez qu'au moment de l'écriture, le type _Span<T>_ n'est pas défini dans la version la plus récente de .NET (4.7.1). Pour l'utiliser, vous devez donc installer le . Package System.Memory de NuGet.

16
Patrick Hofman

À partir de C # 8.0

Le découpage en matrice sera pris en charge, ainsi que les nouveaux types Index et Range ajoutés.

Index i1 = 3;  // number 3 from beginning
Index i2 = ^4; // number 4 from end
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6"

var slice = a[i1..i2]; // { 3, 4, 5 }

le préfixe ^ indique le décompte à partir de la fin du tableau.

Échantillon de code ci-dessus tiré du C # 8.0 blog .

Range et Index fonctionnent également avec des boucles foreach

Range range = 1..4; 
foreach (var name in names[range])

Va parcourir 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é.

15
Remy_rm

Voici une méthode d'extension simple qui renvoie une tranche sous la forme d'un nouveau tableau:

public static T[] Slice<T>(this T[] arr, uint indexFrom, uint indexTo) {
    if (indexFrom > indexTo) {
        throw new ArgumentOutOfRangeException("indexFrom is bigger than indexTo!");
    }

    uint length = indexTo - indexFrom;
    T[] result = new T[length];
    Array.Copy(arr, indexFrom, result, 0, length);

    return result;
}

Ensuite, vous pouvez l'utiliser comme:

byte[] slice = foo.Slice(0, 40);
14
Vladimir Mitrovic

Si vous voulez IEnumerable<byte>, alors

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

Si vous ne voulez pas ajouter LINQ ou d'autres extensions, faites simplement:

float[] subArray = new List<float>(myArray).GetRange(0, 8).ToArray();
8
Dimitris

Vous pouvez utiliser un wrapper autour du tableau d'origine (IList), comme dans ce morceau de code (non testé).

public class SubList<T> : IList<T>
{
    #region Fields

private readonly int startIndex;
private readonly int endIndex;
private readonly int count;
private readonly IList<T> source;

#endregion

public SubList(IList<T> source, int startIndex, int count)
{
    this.source = source;
    this.startIndex = startIndex;
    this.count = count;
    this.endIndex = this.startIndex + this.count - 1;
}

#region IList<T> Members

public int IndexOf(T item)
{
    if (item != null)
    {
        for (int i = this.startIndex; i <= this.endIndex; i++)
        {
            if (item.Equals(this.source[i]))
                return i;
        }
    }
    else
    {
        for (int i = this.startIndex; i <= this.endIndex; i++)
        {
            if (this.source[i] == null)
                return i;
        }
    }
    return -1;
}

public void Insert(int index, T item)
{
    throw new NotSupportedException();
}

public void RemoveAt(int index)
{
    throw new NotSupportedException();
}

public T this[int index]
{
    get
    {
        if (index >= 0 && index < this.count)
            return this.source[index + this.startIndex];
        else
            throw new IndexOutOfRangeException("index");
    }
    set
    {
        if (index >= 0 && index < this.count)
            this.source[index + this.startIndex] = value;
        else
            throw new IndexOutOfRangeException("index");
    }
}

#endregion

#region ICollection<T> Members

public void Add(T item)
{
    throw new NotSupportedException();
}

public void Clear()
{
    throw new NotSupportedException();
}

public bool Contains(T item)
{
    return this.IndexOf(item) >= 0;
}

public void CopyTo(T[] array, int arrayIndex)
{
    for (int i=0; i<this.count; i++)
    {
        array[arrayIndex + i] = this.source[i + this.startIndex];
    }
}

public int Count
{
    get { return this.count; }
}

public bool IsReadOnly
{
    get { return true; }
}

public bool Remove(T item)
{
    throw new NotSupportedException();
}

#endregion

#region IEnumerable<T> Members

public IEnumerator<T> GetEnumerator()
{
    for (int i = this.startIndex; i < this.endIndex; i++)
    {
        yield return this.source[i];
    }
}

#endregion

#region IEnumerable Members

IEnumerator IEnumerable.GetEnumerator()
{
    return GetEnumerator();
}

#endregion

}

7
Rauhotz
byte[] foo = new byte[4096]; 

byte[] bar = foo.Take(40).ToArray();
6
greyline

Pour les tableaux d'octets System.Buffer.BlockCopy vous donnera les meilleures performances.

6
Simon Giles

Vous pouvez utiliser la méthode d'extension Take

var array = new byte[] {1, 2, 3, 4};
var firstTwoItems = array.Take(2);
5
aku

Cela peut être une solution qui:

var result = foo.Slice(40, int.MaxValue);

Alors le résultat est un IEnumerable <IEnumerable <byte >> avec un premier IEnumerable <byte> contient les 40 premiers octets de foo, et un second IEnumerable <byte> conserve le reste.

J'ai écrit une classe de wrapper, l'itération entière est paresseuse, j'espère que cela pourrait aider:

public static class CollectionSlicer
{
    public static IEnumerable<IEnumerable<T>> Slice<T>(this IEnumerable<T> source, params int[] steps)
    {
        if (!steps.Any(step => step != 0))
        {
            throw new InvalidOperationException("Can't slice a collection with step length 0.");
        }
        return new Slicer<T>(source.GetEnumerator(), steps).Slice();
    }
}

public sealed class Slicer<T>
{
    public Slicer(IEnumerator<T> iterator, int[] steps)
    {
        _iterator = iterator;
        _steps = steps;
        _index = 0;
        _currentStep = 0;
        _isHasNext = true;
    }

    public int Index
    {
        get { return _index; }
    }

    public IEnumerable<IEnumerable<T>> Slice()
    {
        var length = _steps.Length;
        var index = 1;
        var step = 0;

        for (var i = 0; _isHasNext; ++i)
        {
            if (i < length)
            {
                step = _steps[i];
                _currentStep = step - 1;
            }

            while (_index < index && _isHasNext)
            {
                _isHasNext = MoveNext();
            }

            if (_isHasNext)
            {
                yield return SliceInternal();
                index += step;
            }
        }
    }

    private IEnumerable<T> SliceInternal()
    {
        if (_currentStep == -1) yield break;
        yield return _iterator.Current;

        for (var count = 0; count < _currentStep && _isHasNext; ++count)
        {
            _isHasNext = MoveNext();

            if (_isHasNext)
            {
                yield return _iterator.Current;
            }
        }
    }

    private bool MoveNext()
    {
        ++_index;
        return _iterator.MoveNext();
    }

    private readonly IEnumerator<T> _iterator;
    private readonly int[] _steps;
    private volatile bool _isHasNext;
    private volatile int _currentStep;
    private volatile int _index;
}
3
Li Zhen

Je ne pense pas que C # supporte la sémantique de Range. Vous pouvez cependant écrire une méthode d'extension, comme:

public static IEnumerator<Byte> Range(this byte[] array, int start, int end);

Mais comme d’autres l’ont dit, si vous n’avez pas besoin de définir un index de départ, alors Take est tout ce dont vous avez besoin.

2
bleevo

Voici une fonction d'extension qui utilise un générique et se comporte comme la fonction PHP array_slice . Le décalage négatif et la longueur sont autorisés.

public static class Extensions
{
    public static T[] Slice<T>(this T[] arr, int offset, int length)
    {
        int start, end;

        // Determine start index, handling negative offset.
        if (offset < 0)
            start = arr.Length + offset;
        else
            start = offset;

        // Clamp start index to the bounds of the input array.
        if (start < 0)
            start = 0;
        else if (start > arr.Length)
            start = arr.Length;

        // Determine end index, handling negative length.
        if (length < 0)
            end = arr.Length + length;
        else
            end = start + length;

        // Clamp end index to the bounds of the input array.
        if (end < 0)
            end = 0;
        if (end > arr.Length)
            end = arr.Length;

        // Get the array slice.
        int len = end - start;
        T[] result = new T[len];
        for (int i = 0; i < len; i++)
        {
            result[i] = arr[start + i];
        }
        return result;
    }
}
1
Brendan Taylor
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace data_seniens
{
    class Program
    {
        static void Main(string[] args)
        {
            //new list
            float [] x=new float[]{11.25f,18.0f,20.0f,10.75f,9.50f, 11.25f, 18.0f, 20.0f, 10.75f, 9.50f };

            //variable
            float eat_sleep_area=x[1]+x[3];
            //print
            foreach (var VARIABLE in x)
            {
                if (VARIABLE < x[7])
                {
                    Console.WriteLine(VARIABLE);
                }
            }



            //keep app run
        Console.ReadLine();
        }
    }
}
0
Ahmad AlSaloum