web-dev-qa-db-fra.com

Le moyen le plus efficace d’ajouter des tableaux en C #?

Je tire des données d'un ActiveX de la vieille école sous la forme de tableaux de doublons. Au départ, je ne connais pas le nombre final d'échantillons que je vais récupérer.

Quel est le moyen le plus efficace de concaténer ces tableaux en C # au fur et à mesure que je les sors du système?

63
Huck

Vous ne pouvez pas ajouter à un tableau réel - la taille d'un tableau est fixée au moment de la création. Au lieu de cela, utilisez un List<T> qui peut grandir comme il le faut.

Vous pouvez également conserver une liste de tableaux et les concaténer uniquement lorsque vous avez tout saisi.

Voir Le billet de blog d'Eric Lippert sur les tableaux pour plus de détails et d'informations que je ne pourrais en fournir de façon réaliste :)

77
Jon Skeet

Je pense que si vous souhaitez combiner deux tableaux du même type dans un troisième tableau, il existe un moyen très simple de le faire.

voici le code:

String[] theHTMLFiles = Directory.GetFiles(basePath, "*.html");
String[] thexmlFiles = Directory.GetFiles(basePath, "*.xml");
List<String> finalList = new List<String>(theHTMLFiles.Concat<string>(thexmlFiles));
String[] finalArray = finalList.ToArray();
28
Michael Bahig

Je recommande la réponse trouvée ici: Comment concaténer deux tableaux en C #?

par exemple.

var z = new int[x.Length + y.Length];
x.CopyTo(z, 0);
y.CopyTo(z, x.Length);
25
GeorgePotter

La concaténation de tableaux est simple avec les extensions linq fournies en standard avec .Net 4

La chose la plus importante à retenir est que linq fonctionne avec les objets IEnumerable<T>, Aussi, pour obtenir un tableau comme résultat, vous devez utiliser la méthode .ToArray() à la fin.

Exemple de concaténation de tableaux à deux octets:

byte[] firstArray = {2,45,79,33};
byte[] secondArray = {55,4,7,81};
byte[] result = firstArray.Concat(secondArray).ToArray();
22
Lenny Woods

La solution semble très amusante, mais il est possible de concaténer des tableaux en seulement deux déclarations. Lorsque vous manipulez des tableaux d'octets volumineux, je suppose qu'il est inefficace d'utiliser une liste chaînée pour contenir chaque octet.

Voici un exemple de code permettant de lire des octets à partir d'un flux et d'étendre un tableau d'octets à la volée:

 octet [] buf = nouvel octet [8192]; 
 octet [] résultat = nouvel octet [0]; 
 int compte = 0; 
 faire 
 {
 count = resStream.Read (buf, 0, buf.Length); 
 if (count! = 0) 
 {
 Array.Resize (réf. résultat, résultat.Longueur + nombre); 
 Tableau.Copie (buf, 0, résultat, résultat.Longueur - décompte, nombre); 
} 
} 
 while (count> 0); // plus de données à lire? 
 resStream.Close (); 
7
Hugo

en utilisant ceci, nous pouvons ajouter deux tableaux sans boucle.

Je pense que si vous souhaitez combiner deux tableaux du même type dans un tableau, il existe un moyen très simple de le faire.

Voici le code:

String[] TextFils = Directory.GetFiles(basePath, "*.txt");
String[] ExcelFils = Directory.GetFiles(basePath, "*.xls");
String[] finalArray = TextFils.Concat(ExcelFils).ToArray();

o

String[] Fils = Directory.GetFiles(basePath, "*.txt");
String[] ExcelFils = Directory.GetFiles(basePath, "*.xls");
Fils = Fils.Concat(ExcelFils).ToArray();
6
SGRao

Si vous pouvez faire une approximation du nombre d'éléments qui seront présents à la fin, utilisez la surcharge du constucteur de liste prenant compte en tant que paramètre. Vous économiserez des duplications de liste coûteuses. Sinon, vous devez payer pour cela.

4
Olmo

Vous pourriez ne pas avoir besoin de concaténer le résultat final dans un tableau contigu. Continuez à ajouter à la liste comme suggéré par Jon. En fin de compte, vous aurez un tableau dentelé (enfin, presque rectangulaire en fait). Lorsque vous devez accéder à un élément par index, utilisez le schéma d'indexation suivant:

double x = list[i / sampleSize][i % sampleSize];

Itération sur tableau en dents de scie est également simple:

for (int iRow = 0; iRow < list.Length; ++iRow) {
  double[] row = list[iRow];
  for (int iCol = 0; iCol < row.Length; ++iCol) {
    double x = row[iCol];
  }
}

Cela vous évite d'allouer de la mémoire et de la copie au détriment d'un accès aux éléments légèrement plus lent. Le gain de performance net dépend de la taille de vos données, des modèles d'accès aux données et des contraintes de mémoire.

4
Constantin

Voici une classe utilisable basée sur ce que Constantin a dit:

class Program
{
    static void Main(string[] args)
    {
        FastConcat<int> i = new FastConcat<int>();
        i.Add(new int[] { 0, 1, 2, 3, 4 });
        Console.WriteLine(i[0]);
        i.Add(new int[] { 5, 6, 7, 8, 9 });
        Console.WriteLine(i[4]);

        Console.WriteLine("Enumerator:");
        foreach (int val in i)
            Console.WriteLine(val);

        Console.ReadLine();
    }
}

class FastConcat<T> : IEnumerable<T>
{
    LinkedList<T[]> _items = new LinkedList<T[]>();
    int _count;

    public int Count
    {
        get
        {
            return _count;
        }
    }

    public void Add(T[] items)
    {
        if (items == null)
            return;
        if (items.Length == 0)
            return;

        _items.AddLast(items);
        _count += items.Length;
    }

    private T[] GetItemIndex(int realIndex, out int offset)
    {
        offset = 0; // Offset that needs to be applied to realIndex.
        int currentStart = 0; // Current index start.

        foreach (T[] items in _items)
        {
            currentStart += items.Length;
            if (currentStart > realIndex)
                return items;
            offset = currentStart;
        }
        return null;
    }

    public T this[int index]
    {
        get
        {
            int offset;
            T[] i = GetItemIndex(index, out offset);
            return i[index - offset];
        }
        set
        {
            int offset;
            T[] i = GetItemIndex(index, out offset);
            i[index - offset] = value;
        }
    }

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
        foreach (T[] items in _items)
            foreach (T item in items)
                yield return item;
    }

    #endregion

    #region IEnumerable Members

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

    #endregion
}
2

La suggestion d'Olmo est très bonne, mais j'ajouterais ceci: si vous n'êtes pas sûr de la taille, il est préférable de la rendre un peu plus grande qu'un peu plus petite. Lorsqu'une liste est pleine, gardez à l'esprit qu'elle doublera sa taille pour ajouter plus d'éléments.

Par exemple: supposons qu'il vous faut environ 50 éléments. Si vous utilisez une taille de 50 éléments et que le nombre final d’éléments est de 51, vous obtiendrez une liste de 100 dimensions avec 49 positions perdues.

0
rgargente