在C#中追加数组的最有效方法?

时间:2008-11-20 09:54:29

标签: c# arrays memory-management

我以双打数组的形式从旧式ActiveX中提取数据。我最初并不知道我将实际检索的样本的最终数量。

当我将这些数组从系统中拉出来时,将这些数组连接在一起的最有效方法是什么?

10 个答案:

答案 0 :(得分:75)

您无法附加到实际数组 - 数组的大小在创建时是固定的。相反,请使用可以根据需要增长的List<T>

或者,保留一个数组列表,只有当你抓住所有数据时才将它们连接起来。

请参阅Eric Lippert's blog post on arrays了解更多详情和见解,而不是我实际提供的内容:)

答案 1 :(得分:26)

我相信如果你有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();

答案 2 :(得分:24)

我建议在此处找到答案:How do I concatenate two arrays in C#?

e.g。

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

答案 3 :(得分:21)

使用符合.Net 4标准的linq扩展,连接数组非常简单

要记住的最大的事情是linq适用于IEnumerable<T>个对象,所以为了得到一个数组作为结果,那么你必须在最后使用.ToArray()方法

连接两个字节数组的示例:

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

答案 4 :(得分:7)

解决方案看起来非常有趣,但可以在两个语句中连接数组。当您处理大字节数组时,我认为使用链接列表来包含每个字节是低效的。

这是一个代码示例,用于从流中读取字节并在运行中扩展字节数组:

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

答案 5 :(得分:6)

  

使用此功能我们可以添加两个数组,但不包含任何循环。

我相信如果你有两个相同类型的数组要组合成一个数组,那么就有一种非常简单的方法。

以下是代码:

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

答案 6 :(得分:4)

如果可以近似计算结尾处的项目数,请使用List计算器的重载,该计数器将计数作为参数。您将节省一些昂贵的列表重复。否则你必须付钱。

答案 7 :(得分:4)

您可能不需要将最终结果连接到连续数组中。相反,请按照Jon的建议继续添加到列表中。最后你会有一个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];
  }
}

这可以节省内存分配和复制,但代价是稍慢的元素访问。这是否会带来净性能增益取决于数据大小,数据访问模式和内存限制。

答案 8 :(得分:2)

这是一个基于康斯坦丁所说的可用类:

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
}

答案 9 :(得分:0)

Olmo的建议非常好,但我想补充一点: 如果你不确定它的大小,那么最好让它稍大一些。当列表已满时,请记住它会将其大小加倍以添加更多元素。

例如:假设您需要大约50个元素。如果您使用50个元素大小且最终元素数量为51,那么您将以100个大小的列表结束,其中包含49个浪费的位置。