在C#中使用List的foreach和传统的for循环

36 浏览
0 Comments

在C#中使用List的foreach和传统的for循环

在C#中,我刚发现没有像C++或Java中的迭代器(iterator)。在C++中,我被告知不要使用索引迭代链表(Linked Lists),因为在每个循环中从第一个节点访问会影响性能。但在C#中似乎只有两个选择。传统的for循环(for-loop)VSforeach循环。

在C#中有什么不同吗?与C++不同,for循环没有性能问题吗?

我还听说foreach会在每次循环迭代中创建新变量,就像Java中一样,所以我不知道哪个适合低端手机。

admin 更改状态以发布 2023年5月21日
0
0 Comments

在C#中有一个迭代器的概念,它是IEnumerable,可以提供对集合的顺序访问。

ListLinkedList都实现了这个接口,在两种情况下没有与索引操作的算法复杂度相关的性能惩罚。

顺便提一下,在.NET中LinkedList没有快速附加操作的好处,因为List在将一个项目添加到列表末尾时具有O(1)的平摊时间,并且List对GC的压力更小,因为它通过指数增长的数组存储进行支持,所以大多数时候您最终使用List

关于List和 '同一变量'问题的性能,我认为以下代码演示了使用场景。

在“同一变量”的检查中,您可以看到对于 “for”,变量在外部范围中,在foreach的迭代器块的最近编译器版本中,变量在内部范围中,需要检查哪个版本更改了这个。这在你制作一个闭包的情况下非常重要,而代码演示了它。

void Main()
{
    var n = 10000000;
    var list = Enumerable.Range(0, n).ToList();
    var array = list.ToArray();
    Test(TestForeach, list, "foreach - List");
    Test(TestFor, list, "for - List");
    Test(TestForeach, array, "foreach - Array");
    Test(TestFor, array, "for - Array");
    TestSameVariableFor();
    TestSameVariableForeach();
}
void TestSameVariableFor()
{
    var sum = 0;
    List actions = new List();
    for (var i = 0; i < 2; i++)
    {
        actions.Add(() => sum += i);
    }
    foreach (var a in actions)
    {
        a();
    }
    Console.WriteLine("For - Sum is {0}", sum);
}
void TestSameVariableForeach()
{
    var sum = 0;
    List actions = new List();
    foreach (var i in Enumerable.Range(0, 2))
    {
        actions.Add(() => sum += i);
    }
    foreach (var a in actions)
    {
        a();
    }
    Console.WriteLine("Foreach - Sum is {0}", sum);
}
void Test(Action> action, List list, string what)
{
    var sw = Stopwatch.StartNew();
    action(list);
    sw.Stop();
    Console.WriteLine("Elapsed {0}, {1}", sw.ElapsedMilliseconds, what);
    Console.WriteLine();
}
void Test(Action action, int[] list, string what)
{
    var sw = Stopwatch.StartNew();
    action(list);
    sw.Stop();
    Console.WriteLine("Elapsed {0}, {1}", sw.ElapsedMilliseconds, what);
    Console.WriteLine();
}
void TestFor(List list)
{
    long sum = 0;
    var count = list.Count;
    for (var i = 0; i < count; i++)
    {
        sum += i;
    }
    Console.WriteLine(sum);
}
void TestForeach(List list)
{
    long sum = 0;
    foreach (var i in list)
    {
        sum += i;
    }
    Console.WriteLine(sum);
}
void TestFor(int[] list)
{
    long sum = 0;
    var count = list.Length;
    for (var i = 0; i < count; i++)
    {
        sum += i;
    }
    Console.WriteLine(sum);
}
void TestForeach(int[] list)
{
    long sum = 0;
    foreach (var i in list)
    {
        sum += i;
    }
    Console.WriteLine(sum);
}

输出:

49999995000000
Elapsed 37, foreach - List
49999995000000
Elapsed 6, for - List
49999995000000
Elapsed 7, foreach - Array
49999995000000
Elapsed 6, for - Array
For - Sum is 4
Foreach - Sum is 1

更新:

这里是描述foreach语义变化的帖子:

为什么C#在foreach中重用变量?

0
0 Comments

这并不能完全回答你的问题,但是还是想指出这个假设是错误的:

在C#中,我刚刚发现没有类似于C ++或Java的迭代器

在C#中,它被称为枚举器,详见IEnumerator

此外,考虑使用传统的for循环的代码示例:

static void Main(string[] args)
{
    var data = new List { 7, 10, 0 };
    for (var it = data.GetEnumerator(); it.MoveNext(); )
    {
        Console.WriteLine(it.Current);
    }
}

无论如何,我不认为有人会像这个示例中那样对列表或IEnumerable进行迭代 🙂

0