Самый эффективный способ добавления массивов в С#?
Я извлекаю данные из ActiveX старой школы в виде массивов двойников. Я изначально не знаю окончательного количества образцов, которые я действительно извлечу.
Каков наиболее эффективный способ объединить эти массивы в С#, когда я вытаскиваю их из системы?
Ответы
Ответ 1
Вы не можете добавить к реальному массиву - размер массива фиксируется во время создания. Вместо этого используйте List<T>
, который может расти по мере необходимости.
Кроме того, сохраните список массивов и соедините их все, только когда вы все схватили.
Смотрите сообщение в блоге Eric Lippert на массивах для более подробной информации и понимания, чем я мог бы реально предоставить:)
Ответ 2
Я считаю, что если у вас есть 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();
Ответ 3
Я рекомендую ответ, найденный здесь: Как объединить два массива в С#?
например.
var z = new int[x.Length + y.Length];
x.CopyTo(z, 0);
y.CopyTo(z, x.Length);
Ответ 4
Конкатенационные массивы просты, используя расширения 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();
Ответ 5
Решение выглядит очень весело, но можно объединить массивы только в двух утверждениях. Когда вы обрабатываете массивы больших байт, я полагаю, что неэффективно использовать связанный список, чтобы содержать каждый байт.
Вот пример кода для чтения байтов из потока и расширения байтового массива на лету:
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();
Ответ 6
, используя это, мы можем добавить два массива с любым циклом.
Я считаю, что если у вас есть 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();
Ответ 7
Если вы можете сделать приближение количества элементов, которые будут там в конце, используйте перегрузку Constuctor List, которая принимает количество в качестве параметра. Вы сэкономите несколько дорогостоящих дубликатов списка. В противном случае вам придется заплатить за это.
Ответ 8
Вам может не понадобиться конкатенация конечного результата в смежный массив. Вместо этого добавьте список в список, предложенный Джоном. В итоге у вас будет jagged array (ну, фактически, почти прямоугольный). Когда вам нужно получить доступ к элементу по индексу, используйте следующую схему индексирования:
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];
}
}
Это экономит ваше распределение памяти и копирование за счет немного более медленного доступа к элементу. Будет ли это увеличение производительности сети, зависит от размера ваших данных, шаблонов доступа к данным и ограничений памяти.
Ответ 9
Вот полезный класс, основанный на том, что сказал Константин:
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
}
Ответ 10
Предложение Olmo очень хорошее, но я бы добавил:
Если вы не уверены в размерах, лучше сделать его немного больше, чем немного меньше. Когда список заполнен, имейте в виду, что он удвоит его размер, чтобы добавить больше элементов.
Например: предположим, что вам понадобится около 50 элементов. Если вы используете размер 50 элементов, а конечное число элементов - 51, вы закончите список размером 100 с 49 потерянными позициями.