2010-08-30 14 views
3

J'ai le tableau contenant des données, disons un en-tête et une donnée réelle. Je dois passer les données contenues dans le tableau à une méthode, mais je veux absolument éviter de le copier dans un autre tableau.Référencement d'une partie d'un tableau en C#

Je pensais à quelque chose comme ArraySegment, mais il ne semble pas fonctionner dans mon cas (ou peut-être que je me trompe?). Donc, comment passer une partie d'un tableau à une méthode, comme c'était un tableau lui-même?

Merci pour vos réponses!

Vive

+0

Qu'est-ce que 'la bonne méthode'? J'utilise actuellement ContrainedCopy. – Jamie

+4

Qu'en est-il de 'ArraySegment' ne fonctionne pas pour vous? –

+0

Vous pourriez également vouloir reconsidérer votre structure de données. L'en-tête et les données réelles sonnent comme deux choses distinctes, qui doivent être conservées séparément. –

Répondre

6

Skip et Take:

var subArray = array.Skip(5).Take(10); 
+1

Bon, mais pas s'il veut maintenir un accès aléatoire par index. –

+0

@Dan Tao, alors il y a la méthode d'extension 'ToArray()'. –

+1

@Darin: À ce stade, vous tombez sur "Je veux absolument éviter de le copier dans un autre tableau". –

3

D'après ce que je peux voir, vous avez deux options:

  1. Modifier la méthode que vous appelez (si vous avez la option). Au lieu de simplement accepter un tableau (ou IEnumerable), vous pouvez lui faire accepter un tableau, un index de départ et un index de fin. Au lieu de passer un tableau, transmettez un objet IEnumerable qui énumère la plage désirée dans votre tableau (sans faire de copie des éléments dans le tableau). Une façon de le faire serait:

var slice = someArray.Skip(startIndex).Take(endIndex - startIndex); 
5

Si vous voulez bâton simplement des tableaux de base (ie int [] chiffres), le moyen le plus efficace est de ont vos fonctions prendre le décalage/compte directement.

Il y a beaucoup de fonctions IO qui font quelque chose de similaire:

readData(data, 0, 4); 

string readData(byte [] buffer, int offset, int length) 

L'autre option consiste à utiliser IEnumberable < T> et SKIP/prendre

readData(data.Skip(0).Take(4)); 

string readData(IEnumerable<byte> buffer) 

Il est important de se rappeler que, dans C# vous n'avez pas affaire à pointeurs, vous avez affaire à objets.

0

Une option consiste à mettre en œuvre quelque chose commeReadOnlyCollection<T> en termes de mise en œuvre IList<T> de façon immuable, mais l'exposer comme une « vue » sur une collection existante, déplacer toute façon appropriée accès à l'index (et avec un nombre approprié, etc.).

Ce serait probablement une classe d'emballage très pratique à avoir autour. Vous devez ensuite modifier votre méthode pour accepter un IList<T> approprié au lieu d'un tableau.

4

J'avais exactement la même idée que Jon Skeet: implémenter un wrapper autour d'un T[] qui fournit un accès aléatoire par index, gérant automatiquement l'ajustement de l'accès indexé pour vous.

j'ai jeté ensemble une mise en œuvre rapide tout à l'heure (passez directement au fond de cette réponse pour une courte démonstration):

public struct ArrayFragment<T> : IList<T> 
{ 
    private T[] _source; 
    private int _start; 
    private int _count; 

    public ArrayFragment(T[] source, int start, int count) 
    { 
     if (source == null) 
     { 
      throw new ArgumentNullException("source"); 
     } 
     if (start < 0 || start >= source.Length) 
     { 
      throw new ArgumentOutOfRangeException("start"); 
     } 
     if (count > source.Length - start) 
     { 
      throw new ArgumentOutOfRangeException("count"); 
     } 

     _source = source; 
     _start = start; 
     _count = count; 
    } 

    public T this[int index] 
    { 
     get { return _source[_start + index]; } 
    } 

    public int Count 
    { 
     get { return _count; } 
    } 

    public bool Contains(T value) 
    { 
     int index = Array.IndexOf(_source, value, _start, _count); 
     return index != -1; 
    } 

    public void CopyTo(T[] destination, int index) 
    { 
     Array.Copy(_source, _start, destination, index, _count); 
    } 

    public int IndexOf(T value) 
    { 
     int index = Array.IndexOf(_source, value, _start, _count); 
     return index != -1 ? index - _start : -1; 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     for (int i = 0; i < _count; ++i) 
     { 
      yield return _source[_start + i]; 
     } 
    } 

    #region Explicit Interface Implementation 

    // a bunch of explicitly implemented IList<T> members 
    // that all throw a NotSupportedException 

    #endregion 
} 

Voici une démo:

int[] numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

try 
{ 
    var fragment = new ArrayFragment<int>(numbers, 2, 5); 

    Console.WriteLine("Iterating using foreach: "); 
    foreach (int number in fragment) 
    { 
     Console.WriteLine(number); 
    } 

    Console.WriteLine("Iterating using for: "); 
    for (int i = 0; i < fragment.Count; ++i) 
    { 
     Console.WriteLine(fragment[i]); 
    } 

    Console.WriteLine("Index of 4: {0}", fragment.IndexOf(4)); 
    Console.WriteLine("Index of 1: {0}", fragment.IndexOf(1)); 
    Console.WriteLine("Index of 9: {0}", fragment.IndexOf(9)); 
    Console.WriteLine("Index of 7: {0}", fragment.IndexOf(7)); 
} 
catch (Exception ex) 
{ 
    Console.WriteLine(ex.ToString()); 
} 

Console.ReadLine(); 

Sortie:

 
Iterating using foreach: 
3 
4 
5 
6 
7 
Iterating using for: 
3 
4 
5 
6 
7 
Index of 4: 1 
Index of 1: -1 
Index of 9: -1 
Index of 7: 4