如何在没有IEnumerable<int>
的情况下将int[]
转换为ToArray()
?我需要一种比ToArray()
更快的方法或功能。
我有一个大的int大型状态和两个小的大型左和右使用方法的Take和Skip。代码:
int[] left = state.Take(pivot).ToArray();
int[] right = state.Skip(pivot).ToArray();
pivot - 分裂点。
答案 0 :(得分:6)
有四种方法可以从int[]
获得IEnumerable<int>
。按速度顺序:
int[]
,然后将其丢回。Count
和CopyTo
的集合类型,使用它。 Linq的ToArray()
不会做第一个,因为ToArray()
旨在保护源免受ToArray()
结果的更改。
其余的,Linq试图选择最快的选择。因此,你不会有太大的进步。
如果您可以接受投射到数组,那么您将能够用以下内容覆盖该情况:
int[] array = intEnum as int[] ?? intEnum.ToArray();
(如果你知道intEnum
总是一个数组,那么你可以直接进行强制转换。相反,如果你知道intEnum
永远不是一个数组,那么上面的速度会慢一点,因为它总是有没有获得实现该方法的好处的尝试成本。)
否则,虽然你不能做得更好,除非你知道可枚举的大小,但它不是ICollection<int>
所以linq不能这样做找到它自己。
修改强>:
评论中添加了评论:
我有一个大的int数组。通过方法的Take and Skip,我把它分成两个大块。
如果您正在使用.NET Core,那么这个案例已经针对上个月合并到祝福存储库中的提交进行了优化,因此如果您使用最新版本的corefx或等待更新,那么您需要&#39已经得到了这个优化。
否则,您可以应用与Linq版本相同的逻辑:
让我们调用我们的源数组sourceArray
。
我们有IEnumerable<int>
var en = sourceArray.Skip(amountSkipped).Take(amountTaken);
如果amountSkipped
或amountTaken
小于零,则此处应使用零。如果省略Skip()
,那么amountSkipped
应该使用零。如果遗漏了Take()
,则应int.MaxValue
使用amountTaken
。
输出数组的大小为:
int count = Math.Min(sourceArray.Length - amountSkipped, amountTaken);
然后我们可以创建并分配到一个数组:
int[] array = new int[count];
int index = 0;
foreach (int item in en)
array[index] = item;
现在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);
根本不需要Skip()
和Take()
。
再次修改:
现在的问题是:
int[] left = state.Take(pivot).ToArray();
int[] right = state.Skip(pivot).ToArray();
我们可以简单地做到这一点:
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);
这确实是一个相当大的进步。
如果我们知道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);
答案 1 :(得分:1)
这在很大程度上取决于IEnumerable背后的实际类型。如果它已经是一个数组,你可以投射它。如果是其他任何东西,除了ToArray()
之外通常无法做到这一点。您可能想要考虑为什么它很慢。也许下面有一个LINQ查询可以进行数据库调用,可以进行优化