创建一个新数组,排除一个项目比创建一个列表并删除它更快?
Creating a new array, discluding an item is faster than creating a list and removing it?
我拼命想找到一种更快的方法来创建一个数组,其中没有一个项目,而不是创建这些对象的列表并删除该项目。
原因是我的数组平均有 5 个项目,大多数时候更少,并且创建一个列表只是为了删除一个我不再想要的项目,对我来说似乎太多了。
自从我前段时间编写了自己的探查器后,我决定将该方法和我想到的另一个方法进行测试,结果很重要。
int[] a1 = new int[] { 1, 2, 3 };
方法 1(创建对象列表并删除第二项):
Profiler.Start("Method 1");
List<int> a2 = new List<int>(a1);
a2.RemoveAt(1);
Profiler.Stop("Method 1");
方法2(创建一个大小相同但为1的数组,并排除第2项):
Profiler.Start("Method 2");
int[] a3 = new int[a1.Length - 1];
int l = 0;
for (int i = 0; i < a1.Length; i++) if (a1[i] != 2) { a3[l] = a1[i]; l++; }
Profiler.Stop("Method 2");
探查器结果:
http://i.stack.imgur.com/al8i6.png
问题
为什么性能差异如此显着?
我从来没有真正花时间研究数组和列表之间的区别。
似乎开销来自列表内容的初始化,而不是来自对 List.RemoveAt()
的调用。
换句话说,List<int> a2 = new List<int>(a1);
行占了时间
这里有一些代码试图消除 List.RemoveAt()
和 Array.Copy()
所花费的时间。
在我的 PC 上发布版本的结果是:
LIST Elapsed: 00:00:00.4724841
ARRAY Elapsed: 00:00:00.4670488
LIST Elapsed: 00:00:00.4714016
ARRAY Elapsed: 00:00:00.4675552
LIST Elapsed: 00:00:00.4703538
ARRAY Elapsed: 00:00:00.4698310
这表明时间非常相似。
测试程序为:
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Demo
{
public static class Program
{
public static void Main()
{
int[] a1 = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
int trials = 3;
int iterations = 10000000;
Stopwatch sw = new Stopwatch();
for (int i = 0; i < trials; ++i)
{
for (int j = 0; j < iterations; ++j)
{
List<int> a2 = new List<int>(a1);
sw.Start();
a2.RemoveAt(1);
sw.Stop();
}
Console.WriteLine("LIST Elapsed: " + sw.Elapsed);
sw.Reset();
for (int j = 0; j < iterations; ++j)
{
int[] a3 = new int[a1.Length - 1];
int l = 0;
sw.Start();
for (int k = 0; k < a1.Length; k++)
{
if (a1[k] != 2)
{
a3[l] = a1[k];
l++;
}
}
sw.Stop();
}
Console.WriteLine("ARRAY Elapsed: " + sw.Elapsed);
sw.Reset();
}
}
}
}
我拼命想找到一种更快的方法来创建一个数组,其中没有一个项目,而不是创建这些对象的列表并删除该项目。
原因是我的数组平均有 5 个项目,大多数时候更少,并且创建一个列表只是为了删除一个我不再想要的项目,对我来说似乎太多了。
自从我前段时间编写了自己的探查器后,我决定将该方法和我想到的另一个方法进行测试,结果很重要。
int[] a1 = new int[] { 1, 2, 3 };
方法 1(创建对象列表并删除第二项):
Profiler.Start("Method 1");
List<int> a2 = new List<int>(a1);
a2.RemoveAt(1);
Profiler.Stop("Method 1");
方法2(创建一个大小相同但为1的数组,并排除第2项):
Profiler.Start("Method 2");
int[] a3 = new int[a1.Length - 1];
int l = 0;
for (int i = 0; i < a1.Length; i++) if (a1[i] != 2) { a3[l] = a1[i]; l++; }
Profiler.Stop("Method 2");
探查器结果:
http://i.stack.imgur.com/al8i6.png
问题 为什么性能差异如此显着?
我从来没有真正花时间研究数组和列表之间的区别。
似乎开销来自列表内容的初始化,而不是来自对 List.RemoveAt()
的调用。
换句话说,List<int> a2 = new List<int>(a1);
行占了时间
这里有一些代码试图消除 List.RemoveAt()
和 Array.Copy()
所花费的时间。
在我的 PC 上发布版本的结果是:
LIST Elapsed: 00:00:00.4724841
ARRAY Elapsed: 00:00:00.4670488
LIST Elapsed: 00:00:00.4714016
ARRAY Elapsed: 00:00:00.4675552
LIST Elapsed: 00:00:00.4703538
ARRAY Elapsed: 00:00:00.4698310
这表明时间非常相似。
测试程序为:
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Demo
{
public static class Program
{
public static void Main()
{
int[] a1 = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
int trials = 3;
int iterations = 10000000;
Stopwatch sw = new Stopwatch();
for (int i = 0; i < trials; ++i)
{
for (int j = 0; j < iterations; ++j)
{
List<int> a2 = new List<int>(a1);
sw.Start();
a2.RemoveAt(1);
sw.Stop();
}
Console.WriteLine("LIST Elapsed: " + sw.Elapsed);
sw.Reset();
for (int j = 0; j < iterations; ++j)
{
int[] a3 = new int[a1.Length - 1];
int l = 0;
sw.Start();
for (int k = 0; k < a1.Length; k++)
{
if (a1[k] != 2)
{
a3[l] = a1[k];
l++;
}
}
sw.Stop();
}
Console.WriteLine("ARRAY Elapsed: " + sw.Elapsed);
sw.Reset();
}
}
}
}