在C#中追加数组最有效的方法?
我正在用双数组的forms从老派的ActiveX中提取数据。 我最初并不知道最终的实际样本数量。
在C#中将这些数组连接在一起的最有效方法是什么?
你不能附加到实际的数组 – 在创build时数组的大小是固定的。 相反,使用List<T>
,它可以根据需要增长。
或者,保存一个数组列表,并将它们连接在一起,只有当你抓住所有东西。
有关详细信息和洞察力,请参阅Eric Lippert关于数组的博客文章,而不是我实际上可以提供的:)
我相信,如果你有两个相同types的数组,你想合并成第三个数组,有一个非常简单的方法来做到这一点。
这是代码:
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();
我build议在这里find的答案: 我如何在C#中连接两个数组?
例如
var z = new int[x.Length + y.Length]; x.CopyTo(z, 0); y.CopyTo(z, x.Length);
使用.Net 4标准的linq扩展来连接数组很简单
要记住的最大的事情是linq与IEnumerable<T>
对象一起工作,所以为了得到一个数组作为结果,那么你必须在.ToArray()
使用.ToArray()
方法
连接两个字节数组的示例:
byte[] firstArray = {2,45,79,33}; byte[] secondArray = {55,4,7,81}; byte[] result = firstArray.Concat(secondArray).ToArray();
该解决scheme看起来非常有趣,但可以用两个语句连接数组。 在处理大型字节数组时,我认为使用链表来包含每个字节是低效的。
下面是一个代码示例,用于从stream中读取字节并实时扩展字节数组:
byte [] buf = new byte [8192]; byte []结果=新字节[0]; int count = 0; 做 { count = resStream.Read(buf,0,buf.Length); 如果(count!= 0) { Array.Resize(ref result,result.Length + count); Array.Copy(buf,0,result,result.Length - count,count); } } while(count> 0); //还有更多数据要读取? resStream.Close();
使用这个我们可以添加任何循环的两个数组。
我相信,如果你有两个相同types的数组,你想合并成一个数组,有一个非常简单的方法来做到这一点。
代码如下:
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();
如果您可以近似地计算最后将出现的项目数,请使用以count为参数的List构造函数的重载。 您将节省一些昂贵的列表重复。 否则,你必须付钱。
您可能不需要将最终结果连接成连续的数组。 相反,不要像Jonbuild议的那样追加到列表中。 最后你会有一个锯齿状的数组 (事实上,几乎是矩形的)。 当您需要通过索引访问元素时,请使用以下索引scheme:
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 }
奥尔莫的build议是非常好的,但我想补充一点:如果你不确定这个尺寸,最好稍大一点。 当列表已满时,请记住它会将其大小加倍以添加更多元素。
例如:假设你将需要大约50个元素。 如果您使用50个元素大小,最后一个元素数量为51,那么您将以100个大小的列表结束,其中包含49个浪费的位置。