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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/304816/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 22:26:44  来源:igfitidea点击:

Most efficient way to append arrays in C#?

c#arraysmemory-management

提问by Huck

I am pulling data out of an old-school ActiveX in the form of arrays of doubles. I don't initially know the final number of samples I will actually retrieve.

我正在以双精度数组的形式从老式 ActiveX 中提取数据。我最初不知道我将实际检索的最终样本数量。

What is the most efficient way to concatenate these arrays together in C# as I pull them out of the system?

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

采纳答案by Jon Skeet

You can't append to an actual array - the size of an array is fixed at creation time. Instead, use a List<T>which can grow as it needs to.

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

Alternatively, keep a list of arrays, and concatenate them all only when you've grabbed everything.

或者,保留一个数组列表,并仅在您获取所有内容后将它们全部连接起来。

See Eric Lippert's blog post on arraysfor more detail and insight than I could realistically provide :)

请参阅Eric Lippert 的关于数组的博客文章,了解我无法实际提供的更多细节和见解:)

回答by Olmo

If you can make an approximation of the number of items that will be there at the end, use the overload of the List constuctor that takes count as a parameter. You will save some expensive List duplications. Otherwise you have to pay for it.

如果您可以估算最后将出现的项目数,请使用将 count 作为参数的 List 构造函数的重载。您将节省一些昂贵的列表重复。否则你必须为此付出代价。

回答by rgargente

Olmo's suggestion is very good, but I'd add this: If you're not sure about the size, it's better to make it a little bigger than a little smaller. When a list is full, keep in mind it will double its size to add more elements.

Olmo 的建议很好,但我要补充一点:如果你不确定尺寸,最好把它弄大一点而不是小一点。当列表已满时,请记住它会将其大小加倍以添加更多元素。

For example: suppose you will need about 50 elements. If you use a 50 elements size and the final number of elements is 51, you'll end with a 100 sized list with 49 wasted positions.

例如:假设您需要大约 50 个元素。如果您使用 50 个元素的大小并且元素的最终数量为 51,您将得到一个 100 大小的列表,其中有 49 个浪费的位置。

回答by Constantin

You might not need to concatenate end result into contiguous array. Instead, keep appending to the list as suggested by Jon. In the end you'll have a jagged array(well, almost rectangular in fact). When you need to access an element by index, use following indexing scheme:

您可能不需要将最终结果连接到连续数组中。相反,按照 Jon 的建议继续添加到列表中。最后你会得到一个锯齿状的数组(嗯,实际上几乎是矩形的)。当您需要通过索引访问元素时,请使用以下索引方案:

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

Iteration over jagged array is also straightforward:

对锯齿状数组的迭代也很简单:

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

This saves you memory allocation and copying at expense of slightly slower element access. Whether this will be a net performance gain depends on size of your data, data access patterns and memory constraints.

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

回答by Jonathan C Dickinson

Here is a usable class based on what Constantin said:

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

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
}

回答by Jonathan C Dickinson

The solution looks like great fun, but it is possible to concatenate arrays in just two statements. When you're handling large byte arrays, I suppose it is inefficient to use a Linked List to contain each byte.

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

Here is a code sample for reading bytes from a stream and extending a byte array on the fly:

这是从流中读取字节并动态扩展字节数组的代码示例:

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

回答by Michael Bahig

I believe if you have 2 arrays of the same type that you want to combine into a third array, there's a very simple way to do that.

我相信如果您有 2 个相同类型的数组想要合并到第三个数组中,那么有一种非常简单的方法可以做到这一点。

here's the code:

这是代码:

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

回答by GeorgePotter

I recommend the answer found here: How do I concatenate two arrays in C#?

我推荐这里的答案:How do I concatenate two array in C#?

e.g.

例如

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

回答by Lenny Woods

Concatenating arrays is simple using linq extensions which come standard with .Net 4

使用 .Net 4 标配的 linq 扩展连接数组很简单

Biggest thing to remember is that linq works with IEnumerable<T>objects, so in order to get an array back as your result then you must use the .ToArray()method at the end

要记住的最重要的事情是 linq 与IEnumerable<T>对象一起使用,因此为了将数组作为结果返回,您必须.ToArray()在最后使用该方法

Example of concatenating two byte arrays:

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

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

回答by SGRao

using this we can add two array with out any loop.

使用这个我们可以添加两个数组而没有任何循环。

I believe if you have 2 arrays of the same type that you want to combine into one of array, there's a very simple way to do that.

我相信如果您有 2 个相同类型的数组想要合并到其中一个数组中,那么有一种非常简单的方法可以做到这一点。

Here's the code:

这是代码:

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

or

或者

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