哪个更好?数组,ArrayList还是List<T>(从性能和速度方面考虑)

22

我需要网页处理速度快。要添加的值的计数将是动态的。

以上哪一种更受推荐?请给出合理的原因。

编辑:例如:

string str = "a,b,c"; //Count of the number of elements in str is not fixed
string[] arr = str.Split(',');

或者,

ArrayList al = new ArrayList();
al.Add(str.Split(','));

9
为什么不自己试一试呢?此外,选择使用Array、ArrayList或List<T>取决于你想要做什么。我会选择最容易使用的那一个,只有在真正需要时才担心性能。 - Kristof Claes
在你的特定情况下尝试每个,进行分析并确定哪一个最适合你的需求。它们各自具有不同的用途。没有一种通用的“这是最好的”答案适用于所有情况。 - Sam Holder
28
我喜欢“过早优化”的气味在早晨。 - Jamiec
2
List<T>ArrayList使用数组作为其支持存储。它们可以和数组一样快(而且确实如此),但不可能更快。 - Sergey Kalinichenko
1
请问有哪些常用的数据结构?例如ArrayList、List、Hashtable、Dictionary、SortedList和SortedDictionary等。它们之间有什么区别?在什么情况下应该使用哪种数据结构? - Tilak
3个回答

26

List<T>通常比ArrayList更优选。

  • 对于值类型,List<T>更快,因为它避免了装箱。
  • 强类型元素

如果您希望向调用者公开的列表是不可变的,则List<T>ArrayList都支持此功能:

List<T>.AsReadOnly()
ArrayList.ReadOnly(ArrayList list);
你的问题涉及到选择使用 ArrayList 还是 List<T>,但你的示例显示的是一个数组,两者并非同一种数据类型。

那么,在什么情况下选择ArrayList比List更好呢? - eaglei22

20

"不可变"集合使用数组,可变集合使用List<T>

  • "不可变"集合 - 仅在创建时更改,之后多次读取。
  • 可变集合 - 经常进行多次更改。

性能统计数据(Array vs List vs ReadonlyCollection):

       Array                List        ReadOnlyCollection         Penalties      Method
00:00:01.3932446    00:00:01.6677450    00:00:06.2444633    1 vs  1,2  vs  4,5   Generate
00:00:00.1856069    00:00:01.0291365    00:00:02.0674881    1 vs  5,5  vs 11,1   Sum
00:00:00.4350745    00:00:00.9422126    00:00:04.5994937    1 vs  2,2  vs 10,6   BlockCopy
00:00:00.2029309    00:00:00.4272936    00:00:02.2941122    1 vs  2,1  vs 11,3   Sort

源代码:

interface IMethods<T>
{
  T Generate(int size, Func<int, int> generator);
   int Sum(T items);
   T BlockCopy(T items);
   T Sort(T items);
}

class ArrayMethods:IMethods<int[]>
{
  public int[] Generate(int size, Func<int, int> generator)
  {
    var items = new int[size];
    for (var i = 0; i < items.Length; ++i)
      items[i] = generator(i);
    return items;
  }
  public int Sum(int[] items)
  {
    int sum = 0;
    foreach (var item in items)
      sum += item;
    return sum;
  }
  public int[] BlockCopy(int[] items)
  {
    var res = new int[items.Length / 2];
    Buffer.BlockCopy(items, items.Length / 4 * sizeof(int), res, 0, res.Length * sizeof(int));
    return res;
  }
  public int[] Sort(int[] items)
  {
    var res = new int[items.Length];
    Buffer.BlockCopy(items, 0, res, 0, items.Length * sizeof(int));
    return res;
  }
}
class ListMethods : IMethods<List<int>>
{
  public List<int> Generate(int size, Func<int, int> generator)
  {
    var items = new List<int>(size);
    for (var i = 0; i < size; ++i)
      items.Add(generator(i));
    return items;
  }
  public int Sum(List<int> items)
  {
    int sum = 0;
    foreach (var item in items)
      sum += item;
    return sum;
  }
  public List<int> BlockCopy(List<int> items)
  {
    var count = items.Count / 2;
    var res = new List<int>(count);
    var start = items.Count / 4;
    for (var i = 0; i < count; ++i)
      res.Add(items[start + i]);
    return res;
  }
  public List<int> Sort(List<int> items)
  {
    var res = new List<int>(items);
    res.Sort();
    return res;
  }
}
class ReadOnlyCollectionMethods:IMethods<ReadOnlyCollection<int>>
{
  public ReadOnlyCollection<int> Generate(int size, Func<int, int> generator)
  {
    return new ReadOnlyCollection<int>(Enumerable.Range(0, size).Select(generator).ToList());
  }

  public int Sum(ReadOnlyCollection<int> items)
  {
    int sum = 0;
    foreach (var item in items)
      sum += item;
    return sum;
  }


  public ReadOnlyCollection<int> BlockCopy(ReadOnlyCollection<int> items)
  {
    return new ReadOnlyCollection<int>(items.Skip(items.Count / 4).Take(items.Count / 2).ToArray());
  }
  public ReadOnlyCollection<int> Sort(ReadOnlyCollection<int> items)
  {
    return new ReadOnlyCollection<int>(items.OrderBy(s => s).ToList());
  }
}

static class Program
{
  static Tuple<string, TimeSpan>[] CheckPerformance<T>(IMethods<T> methods) where T:class
  {
    var stats = new List<Tuple<string, TimeSpan>>();

    T source = null;
    foreach (var info in new[] 
      { 
        new {Name = "Generate", Method = new Func<T, T>(items => methods.Generate(10000000, i => i % 2 == 0 ? -i : i))}, 
        new {Name = "Sum", Method =  new Func<T, T>(items => {Console.WriteLine(methods.Sum(items));return items;})}, 
        new {Name = "BlockCopy", Method = new Func<T, T>(items => methods.BlockCopy(items))}, 
        new {Name = "Sort", Method = new Func<T, T>(items => methods.BlockCopy(items))}, 
        new {Name = "Sum", Method =  new Func<T, T>(items => {Console.WriteLine(methods.Sum(items));return items;})}, 
      }
     )
    {
      int count = 10;
      var stopwatch = new Stopwatch();
      stopwatch.Start();
      T res = null;
      for (var i = 0; i < count; ++i)
        res = info.Method(source);
      stopwatch.Stop();
      source = res;
      stats.Add(new Tuple<string, TimeSpan>(info.Name, stopwatch.Elapsed));
    }
    return stats.ToArray();
  }

  static void Main()
  {
    var arrayStats = CheckPerformance(new ArrayMethods());
    var listStats = CheckPerformance(new ListMethods());
    var rcStats = CheckPerformance(new ReadOnlyCollectionMethods());

    Console.WriteLine("       Array                List        ReadOnlyCollection         Penalties      Method");
    for(var i = 0; i < arrayStats.Length; ++i)
    {
      Console.WriteLine("{0}    {1}    {2}    1 vs {3,4:f1}  vs {4,4:f1}   {5}", arrayStats[i].Item2, listStats[i].Item2, rcStats[i].Item2, 
        listStats[i].Item2.TotalSeconds / arrayStats[i].Item2.TotalSeconds,
        rcStats[i].Item2.TotalSeconds / arrayStats[i].Item2.TotalSeconds, arrayStats[i].Item1);
    }
  }

7
除了数组并非真正不可变之外,IEnumerable<T>IReadOnlyList<T>(在 .Net 4.5 中新增)是不可变的。 - svick
5
数组不是不可变的。相反,使用ReadOnlyCollection<T>来包装一个不可变的List<T>,通常通过调用List<T>.AsReadOnly()实现。 - Joe
6
数组是可变的,在需要不可变性时应避免使用:http://blogs.msdn.com/b/ericlippert/archive/2008/09/22/arrays-considered-somewhat-harmful.aspx - Joshua
2
@DarkGray,事实是,数组不是不可变的,也就是说,在创建后可以修改它(例如myArray[i] = newValue)。至于性能方面,你的统计数据毫无意义,因为它们没有显示如何进行测量。固定大小(即不能添加/删除元素)与不可变(这意味着现有元素也不能被替换)并不相同。 - Joe
2
其中一些测试存在缺陷。例如,您的数组生成函数使用了其大小预先已知的事实。但是,在列表生成中您没有做类似的事情(例如,在List<T>构造函数中使用容量参数)。 - Joe
显示剩余3条评论

9
List <T>ArrayList 总是更快的。 List <T> 不必将添加到其中的值装箱。 ArrayList 只能“接受”对象,这意味着虽然你可以向列表中添加任何对象,但是当你需要这些值时,它们必须由CLR隐式地装箱,然后再由你显式地取消装箱。
编辑: 这里有一个不错的链接

10
仅适用于值类型的情况下才会有“拳击差异”。对于引用类型,两者将相等。 - Servy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接