Самый эффективный способ добавления массивов в C#?


я вытаскиваю данные из старой школы ActiveX в виде массивов двойников. Я изначально не знаю окончательного количества образцов, которые я действительно получу.

каков наиболее эффективный способ объединить эти массивы вместе в C# , когда я вытаскиваю их из системы?

10 62

10 ответов:

вы не можете добавить к фактическому массиву - размер массива фиксируется во время создания. Вместо этого используйте List<T> который может расти по мере необходимости.

кроме того, сохраните список массивов и объедините их все только тогда, когда вы все схватили.

посмотреть сообщение в блоге Эрика Липперта на массивах для более подробной информации и понимания, чем я мог бы реально обеспечить :)

Я верю, что если у вас есть 2 массива того же типа, которые вы хотите объединить в третий массив, есть очень простой способ сделать это.

вот код:

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();

Я рекомендую ответ найден здесь: Как объединить два массива в C#?

например

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

объединение массивов просто с помощью расширений linq, которые входят в стандартную комплектацию .Net 4

самое главное, чтобы помнить, что linq работает с IEnumerable<T> объекты, поэтому для того, чтобы получить массив обратно в ваш результат, то вы должны использовать .ToArray() метод в конце

пример объединения двух байтовых массивов:

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

решение выглядит очень весело, но можно объединить массивы всего в двух операторах. Когда вы обрабатываете большие массивы байтов, я полагаю, что неэффективно использовать связанный список, чтобы содержать каждый байт.

вот пример кода для чтения байтов из потока и расширения массива байтов на лету:

    byte[] buf = new byte[8192];
    byte[] result = new byte[0];
    int count = 0;
    do
    {
        count = resStream.Read(buf, 0, buf.Length);
        if (count != 0)
        {
            Array.Resize(ref result, result.Length + count);
            Array.Copy(buf, 0, result, result.Length - count, count);
        }
    }
    while (count > 0); // any more data to read?
    resStream.Close();

используя это, мы можем добавить два массива без какого-либо цикла.

Я считаю, что если у вас есть 2 массива одного типа, которые вы хотите объединить в один из массивов, есть очень простой способ сделать это.

вот код:

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

или

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

Если вы можете сделать аппроксимацию количества элементов, которые будут там в конце, используйте перегрузку списка constuctor, который принимает count в качестве параметра. Вы сохраните некоторые дорогие дубликаты списка. В противном случае вы должны заплатить за это.

возможно, Вам не нужно объединять конечный результат в непрерывный массив. Вместо добавления в список, как предложил Джон. В конце концов у вас будет многомерном массиве (ну, почти прямоугольный на самом деле). Когда вам нужно получить доступ к элементу по индексу, используйте следующую схему индексации:

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

итерация по зубчатому массиву также проста:

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

это экономит выделение памяти и копирование за счет немного более медленного доступа к элементам. Будет ли это чистый прирост производительности зависит от размера ваших данных, шаблонов доступа к данным и ограничений памяти.

вот полезный класс, основанный на том, что сказал Константин:

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
}

предложение Олмо очень хорошо, но я бы добавил Это: Если вы не уверены в размере, лучше сделать его немного больше, чем немного меньше. Когда список заполнен, имейте в виду, что он удвоит свой размер, чтобы добавить больше элементов.

например: предположим, вам понадобится около 50 элементов. Если вы используете размер 50 элементов, а конечное число элементов равно 51, вы закончите список размером 100 с 49 потерянными позициями.