【问题标题】:Fastest way to extend array扩展数组的最快方法
【发布时间】:2013-06-05 15:21:16
【问题描述】:

我正在寻找扩展数组的最快方法。 无论是仅对 length + 1 还是 length + x 都必须是最快的方式。

这是一个例子:

var arr = new int [200];
for(int = 0; i < 200; i++)
   arr[i] = i;

现在我想从索引位置 20 开始为 5 个项目扩展 arr。

var arr2 = new int [] { 999, 999, 999, 999, 999 }

如何在性能方面使用最快的方式将 arr2 放置在 arr 中?

结果应该是这样的 0,1,2,3,4....20, 999, 999, 999, 999, 999, 21, 22, 23, 24....199

【问题讨论】:

  • 必须是数组吗?你可以使用泛型,比如 List 吗?
  • 当它在生产中时,该数组将保存多少个项目? 200?一万?
  • 很好的相关-SO C# Arrays 资源
  • “最快”?扩展,你的意思是重新维度吗?
  • 您需要插入最快,还是后续访问?换句话说 - 你是做更多的插入,还是对数组进行更多的访问?最佳解决方案始终取决于“您正在做什么”。

标签: c# arrays c#-4.0


【解决方案1】:

创建一个您想要大小的新数组,然后使用静态Array.Copy 方法将原始数组复制到新数组中。

你不能“扩展”一个数组,你只能创建一个更大的数组并将原始数组复制到其中。

此外,请考虑使用 List&lt;int&gt;LinkedList&lt;&gt; 代替数组,除非您需要对内存中的内容进行极其精细的控制。

【讨论】:

  • 我只关心速度,我选择了数组,因为我可能会找到在数组中插入项目而不是列表的最快方法,而且我出于某种原因认为列表是智能数组,我需要的只是速度所以选择了最低级别的纯数组。
  • @snowyhedgehog 总的来说,使用较低级别的技术会比使用较高级别的技术慢,除非您真的知道自己在做什么。除非您对使用这些工具有丰富的经验,否则更容易在脚上开枪或不正确地使用工具,从而导致效率低得多。
  • 如果经常插入,最好使用List或者LinkedList。如果您不需要按索引访问(即您总是使用 foreach 进行迭代),LinkedList 可能会给您带来最佳的性能优势(以使用更多内存为代价)
  • @Jodrell: Buffer.BlockCopy 很危险,因为您需要提供字节偏移量,而不是数组索引
  • @RobSiklos 实际上一般不会。 LinkedList 导致几乎为零的内存局部性,因此每次迭代列表时都会刷新缓存,导致它比迭代数组或列表慢很多,除了使用更多内存。如果您只需要在开头或结尾添加,那么您可能想要使用StackQueue,或者如果您需要在两端添加/删除,则使用双端队列。这些数据结构将在底层实现为数组,以维护内存局部性。
【解决方案2】:

使用 List 要容易得多。但是如果必须使用数组,则必须创建大小为 205 的新数组并从两个源数组中复制值,因为数组大小是恒定的。

【讨论】:

  • 我必须转移项目,我希望在 c# 中尽可能快
  • @snowyhedgehog,你是什么意思,“转移项目”?
  • 看看我的问题中的结果。索引号为 20 的所有项目都向右移动了 5 个位置。
  • @snowyhedgehog 这表明您可能没有使用正确的数据结构。也许您应该使用Queue 之类的东西。
【解决方案3】:

最好的办法是使用List&lt;int&gt; 之类的东西而不是数组。但如果你必须使用数组:

int[] arr1 = new int[200];
// initialize array
int[] arr2 = new int[]{999, 999, 999, 999, 999};

int targetPos = 20;

// resizes the array, copying the items
Array.Resize(ref arr1, arr1.Length + arr2.Length);

// move the tail of the array down
Buffer.BlockCopy(arr1, 4*targetPos, arr1, 4*(targetPos+arr2.Length), 4*(arr1.Length - targetPos));

// copy arr2 to the proper position
Buffer.BlockCopy(arr2, 0, 4*arr1.targetPos, 4*arr2.Length);

像这样创建一个新数组并复制项目可能会更快。

int[] newArray = new int[arr1.Length + arr2.Length];

// copy first part of original array
Buffer.BlockCopy(arr1, 0, newArray, 0, 4*targetPos);

// copy second array
Buffer.BlockCopy(arr2, 0, newArray, 4*targetPos, 4*arr2.Length);

// copy remainder of original array
Buffer.blockCopy(arr1, 4*targetPos, newArray, 4*(targetPos + arr2.Length), 4*(arr1.Length - targetPos));

// and replace the original array
arr1 = newArray;

哪个版本更快取决于targetPos 的位置。当targetPos 较小时,第二个版本会更快。当targetPos 较小时,第一个版本要复制大量数据两次。第二个版本从不复制超过它必须复制的内容。

BlockCopy 使用起来有点痛苦,因为它需要字节偏移,这就是代码中所有乘以 4 的原因。在上面的第二个版本中使用Array.Copy 可能会更好。这将防止您必须将所有内容乘以 4(有时会忘记)。

【讨论】:

    【解决方案4】:

    如果您知道数组将其维数到该长度的长度,

    var ints  = new int[someFixedLength];
    

    如果您对长度有一个模糊的概念,请使用通用列表。

    var ints = new List<int>(someVagueLength);
    

    这两种类型都实现了IList,但是List 类型处理内部数组的尺寸调整通常是“最快”的方式。


    注意:List 的初始 .Count 将是 0,但内部数组的大小将根据您传递给构造函数的大小进行调整。


    如果你需要在数组之间复制数据,最快的方法是Buffer.BlockCopy,所以从你的例子中

    Buffer.BlockCopy(arr2, 0, arr, sizeof(int) * 20, sizeof(int) * 5);
    

    将所有5 ints 从arr2 复制到2021 ... 24arr 中。

    使用 c#(目前)没有更快的方法来做到这一点。

    【讨论】:

      【解决方案5】:

      此处给出了显示时序基准的答案:Best way to combine two or more byte arrays in C#。如果将“插入的数组”视为数组 1 和 3,将“要插入的数组”视为数组 2,则直接适用“连接三个数组”的示例。

      请注意已接受答案末尾的要点:创建速度更快的方法会产生访问速度较慢的数组(这就是为什么我问您是否关心创建速度或访问速度)。

      【讨论】:

        【解决方案6】:

        使用 System.Linq,您可以通过向数组添加一个新对象来扩展数组...

        int[] intA = new int[] { 1, 2, 3 };
        int intB = 4;
        
        intA = intA.Union(new int[] { intB }).ToArray();
        

        ...或者您可以通过向其添加另一个项目数组来扩展数组...

        int[] intA = new int[] { 1, 2, 3 };
        int[] intB = new int[] { 4, 5, 6 };
        
        intA = intA.Union(intB).ToArray();
        

        ...或者如果您不关心重复...

        int[] intA = new int[] { 1, 2, 3 };
        int[] intB = new int[] { 4, 5, 6 };
        
        intA = intA.Concat(intB).ToArray();
        

        【讨论】:

        • 注意,问题是关于在位置添加,而不仅仅是连接。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-09
        • 1970-01-01
        • 1970-01-01
        • 2014-05-13
        • 2018-04-21
        • 2010-11-25
        • 1970-01-01
        相关资源
        最近更新 更多