代码之家  ›  专栏  ›  技术社区  ›  billmaya

迭代强类型泛型List<T>的最佳方法是什么?

  •  17
  • billmaya  · 技术社区  · 16 年前

    在C#中迭代强类型泛型List的最佳方法是什么。NET和VB.NET?

    7 回复  |  直到 16 年前
        1
  •  32
  •   Steven Sudit    15 年前

    对于C#:

    foreach(ObjectType objectItem in objectTypeList)
    {
        // ...do some stuff
    }
    

    VB.NET的答案来自 紫蚁 :

    For Each objectItem as ObjectType in objectTypeList
        'Do some stuff '
    Next
    
        2
  •  21
  •   Keith    15 年前

    对于IEnumerable的任何通用实现,最好的方法是:

    //C#
    foreach( var item in listVariable) {
        //do stuff
    }
    

    然而,有一个重要的例外。IEnumerable涉及Currents()和MoveNext()的开销,这是foreach循环实际编译的内容。

    当你有一个简单的结构数组时:

    //C#
    int[] valueTypeArray;
    for(int i=0; i < valueTypeArray.Length; ++i) {
         int item = valueTypeArray[i];
         //do stuff
    }
    

    更快。


    更新

    在与@Steven Sudit讨论后(见评论),我认为我最初的建议可能已经过时或错误,所以我做了一些测试:

    // create a list to test with
    var theList = Enumerable.Range(0, 100000000).ToList();
    
    // time foreach
    var sw = Stopwatch.StartNew();
    foreach (var item in theList)
    {
        int inLoop = item;
    }
    Console.WriteLine("list  foreach: " + sw.Elapsed.ToString());
    
    sw.Reset();
    sw.Start();
    
    // time for
    int cnt = theList.Count;
    for (int i = 0; i < cnt; i++)
    {
        int inLoop = theList[i];
    }
    Console.WriteLine("list  for    : " + sw.Elapsed.ToString());
    
    // now run the same tests, but with an array
    var theArray = theList.ToArray();
    
    sw.Reset();
    sw.Start();
    
    foreach (var item in theArray)
    {
        int inLoop = item;
    }
    Console.WriteLine("array foreach: " + sw.Elapsed.ToString());
    
    sw.Reset();
    sw.Start();
    
    // time for
    cnt = theArray.Length;
    for (int i = 0; i < cnt; i++)
    {
        int inLoop = theArray[i];
    }
    Console.WriteLine("array for    : " + sw.Elapsed.ToString());
    
    Console.ReadKey();
    

    因此,我在发布时进行了所有优化:

    list  foreach: 00:00:00.5137506
    list  for    : 00:00:00.2417709
    array foreach: 00:00:00.1085653
    array for    : 00:00:00.0954890
    

    然后调试而不进行优化:

    list  foreach: 00:00:01.1289015
    list  for    : 00:00:00.9945345
    array foreach: 00:00:00.6405422
    array for    : 00:00:00.4913245
    

    因此,它看起来相当一致, for foreach 数组比通用列表更快。

    然而,这涉及100000000次迭代,最快和最慢方法之间的差异约为0.4秒。除非你正在进行大规模的性能关键循环,否则不值得担心。

        3
  •  5
  •   Adam Lassek    15 年前

    C

    myList<string>().ForEach(
        delegate(string name)
        {
            Console.WriteLine(name);
        });
    

    匿名委托目前尚未在VB.Net中实现,但C#和VB.Net都应该能够执行lambdas:

    C

    myList<string>().ForEach(name => Console.WriteLine(name));
    

    VB.Net

    myList(Of String)().ForEach(Function(name) Console.WriteLine(name))
    

    正如Grauenwolf所指出的,由于lambda不返回值,上述VB无法编译。像其他人建议的那样,一个正常的ForEach循环可能是目前最简单的,但像往常一样,它需要一段代码来完成C#在一行中可以完成的事情。


    这里有一个老生常谈的例子,说明为什么这可能有用:这使您能够从IEnumerable存在的另一个作用域传递循环逻辑,因此如果您不想公开它,甚至不必公开它。

    假设你有一个相对url路径列表,你想将其设置为绝对路径:

    public IEnumerable<String> Paths(Func<String> formatter) {
        List<String> paths = new List<String>()
        {
            "/about", "/contact", "/services"
        };
    
        return paths.ForEach(formatter);
    }
    

    所以你可以这样调用函数:

    var hostname = "myhost.com";
    var formatter = f => String.Format("http://{0}{1}", hostname, f);
    IEnumerable<String> absolutePaths = Paths(formatter);
    

    给你 "http://myhost.com/about", "http://myhost.com/contact" 等等显然,在这个特定的例子中,有更好的方法来实现这一点,我只是想演示一下基本原理。

        4
  •  4
  •   Brian G Swanson    16 年前

    对于VB.NET:

    For Each tmpObject as ObjectType in ObjectTypeList
        'Do some stuff '
    Next
        5
  •  2
  •   Matt Hamilton    16 年前

    在不知道列表的内部实现的情况下,我认为通常迭代它的最佳方法是foreach循环。因为foreach使用IEnumerator遍历列表,所以如何从一个对象移动到另一个对象取决于列表本身。

    如果内部实现是一个链表,那么简单的for循环会比foreach慢得多。

    这有道理吗?

        6
  •  2
  •   jfs    16 年前

    这取决于您的应用程序:

    • 对于循环,如果效率是优先事项
    • foreach循环或foreach方法,以更清楚地传达您的意图为准
        7
  •  1
  •   Dan Herbert    16 年前

    我可能遗漏了一些东西,但如果你使用我下面的例子,迭代一个通用列表应该相当简单。名单<>类实现了IList和IEnumerable接口,因此您可以轻松地以任何方式迭代它们。

    最有效的方法是使用for循环:

    for(int i = 0; i < genericList.Count; ++i) 
    {
         // Loop body
    }
    

    您也可以选择使用foreach循环:

    foreach(<insertTypeHere> o in genericList)
    {
        // Loop body
    }