【发布时间】:2014-03-03 13:07:25
【问题描述】:
对于一个项目,我必须经常取包含大量数据的数组的最后 N 个元素。
我试着做
myArray.Skip(myArray.Length - toTake).Take(toTake)
但我发现它很慢。
我把它和这个做了比较:
public static int[] TakeLast(this int[] inputArray, int count)
{
int[] returnArray = new int[count];
int startIndex = Math.Max(inputArray.Count() - count, 0);
unsafe
{
fixed (int* itemArrayPtr = &(inputArray[startIndex]))
{
fixed (int* arrayPtr = &(returnArray[0]))
{
int* itemValuePtr = itemArrayPtr;
int* valuePtr = arrayPtr;
for (int i = 0; i < count; i++)
{
*valuePtr++ = *itemValuePtr++;
}
}
}
}
return returnArray;
}
这很好用,因为它不能是通用的(我希望这可以适用于任何原始类型(int、float、double、...)。
有没有办法通过 generic/linq/... 方法实现相当的性能?我不需要让它在 IEnumerable 上工作,Array 对我来说就足够了。
编辑 我目前正在测试你给我的所有方法,现在是 Array.Copy 似乎更快:
Generating array for 100000000 elements.
SkipTake: 00:00:00.3009047
Unsafe: 00:00:00.0006289
Array.Copy: 00:00:00.0000012
Buffer.BlockCopy: 00:00:00.0001860
Reverse Linq: 00:00:00.2201143
Finished
【问题讨论】:
-
new T[count]后跟Array.Copy?顺便说一句,一个演示Enumerable.Skip/Enumerable.Take速度慢的简短程序会很棒,这样可以实际测试建议的替代方案,而不是主要猜测。 -
是的,我原以为 Array.Copy() 会和指针运算一样快,因为它可能在实现中使用 memcpy 等效项。
-
我认为这不会产生明显的影响,但您无需致电
Take()。如果你只使用myArray.Skip(myArray.Length - toTake),性能会提高很多吗? -
@hvd:请将此作为答案发布。速度之快令人惊讶
-
@BACON 好点,我在没有
Take()的情况下对其进行了测试,但似乎仍然很慢
标签: c# arrays performance linq