繁体   English   中英

C#中foreach循环中的计数器

[英]Counter in foreach loop in C#

foreach的工作:据我所知,

foreach是一个循环,它逐个遍历集合或数组,从0索引开始直到集合的最后一项。

所以,如果我在数组中有n个项目。

foreach (var item in arr)
{

}  

然后,在第一次迭代中, item = arr [0];
然后,在第2, item = arr [1];



在last(nth), item = arr [n-1];

结论:从工作开始,它似乎在每次迭代时都知道从数组中取出哪个值,或者它知道要从数组中获取的项的索引。

现在我的问题是:如何在不使用新变量的情况下获取项目的索引?

foreach (string item in mylist)
{
   if (item == "myitem")
   {
       // get index of item
       break;
   }
}

这取决于你的意思“它”。 迭代器知道它到达了什么索引,是 - 在List<T>或数组的情况下。 IEnumerator<T>没有通用索引。 它是否在索引集合上进行迭代取决于实现。 大量集合不支持直接索引。

(事实上​​, foreach并不总是使用迭代器。如果集合的编译时类型是一个数组,编译器将使用array[0]array[1]等迭代它。同样,集合可以有一个名为GetEnumerator()的方法,它返回一个具有相应成员的类型,但看不到任何IEnumerable / IEnumerator实现。)

维护索引的选项:

  • 使用for循环
  • 使用单独的变量
  • 使用投影将每个项目投影到索引/值对,例如

      foreach (var x in list.Select((value, index) => new { value, index })) { // Use x.value and x.index in here } 
  • 使用我的SmartEnumerable类,它有点像以前的选项

除了第一个选项外,其他所有选项都可以使用,无论该集合是否自然编入索引。

for代替foreach foreach不公开它的内部工作,它枚举任何IEnumerable (它根本没有索引)。

for (int i=0; i<arr.Length; i++)
{
    ...
}

此外,如果你要做的是找到列表中特定项目的索引,则不必自己迭代它。 请改用Array.IndexOf(item)

您对foreach理解不完整。

它适用于暴露IEnumerable (或实现GetEnumerable方法)并使用返回的IEnumerator迭代集合中的项的任何类型。

Enumerator器如何执行此操作(使用索引, yield语句或魔术)是一个实现细节。

为了达到你想要的效果,你应该使用for循环:

for (int i = 0; i < mylist.Count; i++)
{
}

注意:

获取列表中的项目数量会略有不同,具体取决于列表的类型

For Collections: Use Count   [property]
For Arrays:      Use Length  [property]
For IEnumerable: Use Count() [Linq method]

或者更简单,如果你不想使用很多linq并且由于某种原因不想使用for循环。

int i = 0;
foreach(var x in arr)
{
   //Do some stuff
   i++;
}

可能毫无意义,但......

foreach (var item in yourList.Select((Value, Index) => new { Value, Index }))
{
    Console.WriteLine("Value=" + item.Value + ", Index=" + item.Index);
}

只有在迭代数组时才会出现这种情况; 如果您正在迭代不具有索引访问概念的不同类型的集合,该怎么办? 在数组的情况下,保留索引的最简单方法是简单地使用vanilla for循环。

没有自定义Foreach版本:

datas.Where((data, index) =>
{
    //Your Logic
    return false;
}).Any();

在一些简单的例子中,我的方式是使用where + false + any
它比foreach + select((data,index)=>new{data,index}) ,并且没有自定义的Foreach方法。

MyLogic:

  • 使用语句体运行你的逻辑。
  • 因为返回false ,新的可枚举数据计数为零。
  • 使用Any()让yeild运行。

基准测试代码

[RPlotExporter, RankColumn]
public class BenchmarkTest
{
    public static IEnumerable<dynamic> TestDatas = Enumerable.Range(1, 10).Select((data, index) => $"item_no_{index}");

    [Benchmark]
    public static void ToArrayAndFor()
    {
        var datats = TestDatas.ToArray();
        for (int index = 0; index < datats.Length; index++)
        {
            var result = $"{datats[index]}{index}";
        }
    }

    [Benchmark]
    public static void IEnumrableAndForach()
    {
        var index = 0;
        foreach (var item in TestDatas)
        {
            index++;
            var result = $"{item}{index}";
        }
    }

    [Benchmark]
    public static void LinqSelectForach()
    {
        foreach (var item in TestDatas.Select((data, index) => new { index, data }))
        {
            var result = $"{item.data}{item.index}";
        }
    }

    [Benchmark]
    public static void LinqSelectStatementBodyToList()
    {
        TestDatas.Select((data, index) =>
        {
            var result = $"{data}{index}";
            return true;
        }).ToList();
    }

    [Benchmark]
    public static void LinqSelectStatementBodyToArray()
    {
        TestDatas.Select((data, index) =>
        {
            var result = $"{data}{index}";
            return true;
        }).ToArray();
    }

    [Benchmark]
    public static void LinqWhereStatementBodyAny()
    {
        TestDatas.Where((data, index) =>
        {
            var result = $"{data}{index}";
            return false;
        }).Any();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var summary = BenchmarkRunner.Run<BenchmarkTest>();

        System.Console.Read();
    }
}

基准结果:

                         Method |     Mean |     Error |    StdDev | Rank |
------------------------------- |---------:|----------:|----------:|-----:|
                  ToArrayAndFor | 4.027 us | 0.0797 us | 0.1241 us |    4 |
            IEnumrableAndForach | 3.494 us | 0.0321 us | 0.0285 us |    1 |
               LinqSelectForach | 3.842 us | 0.0503 us | 0.0471 us |    3 |
  LinqSelectStatementBodyToList | 3.822 us | 0.0416 us | 0.0389 us |    3 |
 LinqSelectStatementBodyToArray | 3.857 us | 0.0764 us | 0.0785 us |    3 |
      LinqWhereStatementBodyAny | 3.643 us | 0.0693 us | 0.0712 us |    2 |

并非所有集合都有索引。 例如,我可以使用带foreachDictionary (并遍历所有键和值),但我不能使用dictionary[0]dictionary[1]等来编写单个元素。

如果我确实想要遍历字典并跟踪索引,我必须使用一个单独的变量,我自己增加。

在foreach循环中迭代的序列可能不支持索引或知道这样一个概念,它只需要实现一个名为GetEnumerator的方法,该方法返回一个对象,该对象至少具有IEnumerator的接口,尽管不需要它。 如果您知道迭代的内容确实支持索引并且您需要索引,那么我建议使用for循环。

可以在foreach使用的示例类:

    class Foo {

        public iterator GetEnumerator() {
            return new iterator();
        }

        public class iterator {
            public Bar Current {
                get{magic}
            }

            public bool MoveNext() {
                incantation
            }
        }
    }

来自MSDN:

foreach语句为数组中的每个元素或实现System.Collections.IEnumerable或System.Collections.Generic.IEnumerable(Of T)接口的对象集合重复一组嵌入式语句。

所以,它不一定是Array。 它甚至可能是一个懒惰的集合,不知道集合中的项目数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM