C#中foreach循环中的计数器

时间:2010-12-02 17:02:49

标签: c# foreach counter

foreach的工作: 据我所知,

  

foreach是一个循环,循环遍历集合或数组   一,从0指数开始直到   该系列的最后一项。

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

foreach (var item in arr)
{

}  

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



在最后(第n个), item = arr [n-1];

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

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

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

10 个答案:

答案 0 :(得分:77)

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

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

维护索引的选项:

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

    for
  • 使用我的SmartEnumerable课程,这有点像上一个选项

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

答案 1 :(得分:18)

使用for代替foreachforeach不公开其内部工作,它枚举任何IEnumerable(根本不需要索引)。

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

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

答案 2 :(得分:11)

您对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]

答案 3 :(得分:7)

如果您不想使用大量的linq并且出于某种原因不想使用for循环,那就更简单了。

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

答案 4 :(得分:2)

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

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

答案 5 :(得分:1)

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

答案 6 :(得分:1)

没有自定义Foreach版本:

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

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

MyLogic:

  
      
  • 使用声明正文运行您的逻辑。
  •   
  • 因为返回false ,所以新的可枚举数据计数为零。
  •   
  • 使用 Any()让运行。
  •   

基准测试代码

[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 |

答案 7 :(得分:0)

并非所有集合都有索引。例如,我可以使用带有Dictionary的{​​{1}}(并遍历所有键和值),但我无法使用foreach,{{1}来编写单个元素等等。

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

答案 8 :(得分:0)

在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
            }
        }
    }

答案 9 :(得分:0)

来自MSDN:

  

foreach声明重复了一个小组   每个的嵌入式语句   数组或对象中的元素   实现的集合   System.Collections.IEnumerable或   System.Collections.Generic.IEnumerable(中   T)界面。

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