不使用ToArray()将IEnumerable <int>转换为int []

Que*_*ion -6 c# ienumerable toarray

我如何转换IEnumerable<int>int[]没有ToArray()?我需要一种比它更快的方法或功能ToArray().我有一个很大的INT大规模的状态和两个小块状的的使用方法的采取和跳过.码:

 int[] left = state.Take(pivot).ToArray();
 int[] right = state.Skip(pivot).ToArray();
Run Code Online (Sandbox Code Playgroud)

枢轴 - 分裂点.

Jon*_*nna 6

有四种方法可以获得int[]一个IEnumerable<int>.按速度顺序:

  1. 它已经是一个int[],反过来.
  2. 它是一个具有自己的集合类型,CountCopyTo使用它.
  3. 它是一种类型,您可以找到它的大小,分配该大小的数组,并通过迭代源来填充它.
  4. 分配一个数组,填充它但是如果你到达终点然后重新分配一个新数组并复制.继续这样做直到完成,然后在必要时修剪数组.

Linq ToArray()不会做第一个,因为ToArray()它意味着保护源免受结果的影响ToArray().

其余的,Linq试图选择最快的选择.因此,您不会得到太多改进.

如果您可以接受投射到阵列,那么您将能够通过以下方式覆盖该案例:

int[] array = intEnum as int[] ?? intEnum.ToArray();
Run Code Online (Sandbox Code Playgroud)

(如果你知道intEnum它总是一个数组,那么你可以直接进行转换.相反,如果你知道intEnum它永远不是一个数组,那么上面只是慢一点,因为它总是有成本而没有获得实现这种方法的好处).

否则,虽然你不能做得更好,除非在你知道可枚举的大小的情况下,但它不是一个ICollection<int>如此linq无法找到它本身.

编辑:

评论中添加了评论:

我有一个大的int数组.通过方法的Take和Skip,我把它分成两个大块.

如果您正在使用.NET Core,那么这个案例已经针对上个月合并到祝福存储库中的提交进行了优化,因此如果您使用最新版本的corefx或等待更新,那么您已经对此进行了优化.

否则,您可以应用与Linq版本相同的逻辑:

我们来调用我们的源数组sourceArray.

我们有IEnumerable<int>类似的东西var en = sourceArray.Skip(amountSkipped).Take(amountTaken);

如果amountSkippedamountTaken小于零,则此处应使用零.如果Skip()遗漏了那么应该使用零amountSkipped.如果Take()遗漏了那么int.MaxValue应该用于amountTaken.

输出数组的大小为:

int count = Math.Min(sourceArray.Length - amountSkipped, amountTaken);
Run Code Online (Sandbox Code Playgroud)

然后我们可以创建并分配给一个数组:

int[] array = new int[count];
int index = 0;
foreach (int item in en)
  array[index] = item;
Run Code Online (Sandbox Code Playgroud)

现在array将填充而无需分配和修剪,节省大致log count分配.这确实会更快.

但是,如果您使用最新的corefx,那么这已经为您完成了,并进一步优化了能够避免枚举器分配.

尽管如此,如果所做的一切都是Skip,Take那么你可以完全放弃并直接操作:

int count = Math.Min(sourceArray.Length - amountSkipped, amountTaken);
int[] array = new int[count];
Array.Copy(sourceArray, amountSkipped, array, 0, count);
Run Code Online (Sandbox Code Playgroud)

没有必要Skip()Take()根本.

再次编辑:

现在的问题是:

int[] left = state.Take(pivot).ToArray();
int[] right = state.Skip(pivot).ToArray();
Run Code Online (Sandbox Code Playgroud)

我们可以简单地说:

int leftCount = Math.Min(state.Length, Math.Max(pivot, 0));
int[] left = new int[leftCount];
Array.Copy(state, 0, left, 0, leftCount);

int rightCount = Math.Min(state.Length - leftCount);
int[] right = new int[rightCount];
Array.Copy(state, leftCount, right, 0, rightCount);
Run Code Online (Sandbox Code Playgroud)

这确实是一个相当大的改进.

如果我们知道pivot介于0和之间state.Length,那么我们可以使用更简单的:

int[] left = new int[pivot];
Array.Copy(state, 0, left, 0, pivot);

int[] right = new int[state.Length - pivot];
Array.Copy(state, pivot, right, 0, state.Length - pivot);
Run Code Online (Sandbox Code Playgroud)