Самый эффективный способ добавления массивов в C#?
я вытаскиваю данные из старой школы ActiveX в виде массивов двойников. Я изначально не знаю окончательного количества образцов, которые я действительно получу.
каков наиболее эффективный способ объединить эти массивы вместе в C# , когда я вытаскиваю их из системы?
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 потерянными позициями.