Counter in foreach loop in C#
前臂工作:正如我所知,
foreach is a loop which iterates through a collection or array one by
one, starting from 0 index till the
last item of the collection.
所以,如果数组中有n个项。
1 2 3 4 | foreach (var item in arr) { } |
然后,在第1次迭代中,item=arr[0];然后,在第二个,item=arr[1];...在最后(nth),item=arr[n-1];
结论:通过工作,似乎在每次迭代中,它都知道要从数组中获取哪个值,或者它知道要从数组中获取的项的索引。
现在我的问题是:如何在不使用新变量的情况下获得一个项目的索引?
1 2 3 4 5 6 7 8 | foreach (string item in mylist) { if (item =="myitem") { // get index of item break; } } |
这取决于你所说的"它"是什么意思。迭代器知道它到达了什么索引,是的——在
(实际上,
维护索引的选项:
- 使用
for 循环 - 使用单独的变量
使用将每个项投影到索引/值对的投影,例如
1
2
3
4foreach (var x in list.Select((value, index) => new { value, index }))
{
// Use x.value and x.index in here
}使用我的
SmartEnumerable 类,这有点像前面的选项。
除了第一个选项以外,其他所有选项都可以工作,不管集合是否自然索引。
用
1 2 3 4 | for (int i=0; i<arr.Length; i++) { ... } |
此外,如果您要做的是在列表中找到一个特定项的索引,那么您完全不需要自己迭代它。用
您对EDOCX1 1的理解是不完整的。
它适用于公开EDCOX1×3(或实现EDCOX1×7)方法的任何类型,并使用返回的EDCOX1引用8迭代来遍历集合中的项。
EDOCX1 9如何使用这个索引(使用索引、EDCOX1、10、语句或魔术)是一个实现细节。
为了实现你想要的,你应该使用EDCOX1×0循环:
1 2 3 | for (int i = 0; i < mylist.Count; i++) { } |
注:
根据列表的类型,获取列表中的项目数略有不同
1 2 3 | For Collections: Use Count [property] For Arrays: Use Length [property] For IEnumerable: Use Count() [Linq method] |
或者更简单,如果您不想使用大量的LINQ,并且出于某种原因不想使用for循环。
1 2 3 4 5 6 | int i = 0; foreach(var x in arr) { //Do some stuff i++; } |
可能毫无意义,但是…
1 2 3 4 | foreach (var item in yourList.Select((Value, Index) => new { Value, Index })) { Console.WriteLine("Value=" + item.Value +", Index=" + item.Index); } |
不带自定义foreach版本:
1 2 3 4 5 | datas.Where((data, index) => { //Your Logic return false; }).Any(); |
在一些简单的例子中,我的方法是使用
MyLogic:
- use statement body run your logic.
- because return false,new Enumrable data count is zero.
- use Any() let yeild run.
基准测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | [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(); } } |
基准结果:
1 2 3 4 5 6 7 8 | 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 | |
只有当您在迭代数组时,这才是正确的;如果您在迭代一种不同类型的集合,而该集合没有按索引访问的概念,该怎么办?在数组的情况下,保持索引的最简单方法是简单地使用一个普通的for循环。
来自MSDN:
The foreach statement repeats a group
of embedded statements for each
element in an array or an object
collection that implements the
System.Collections.IEnumerable or
System.Collections.Generic.IEnumerable(Of
T) interface.
所以,它不一定是数组。它甚至可能是一个懒惰的集合,不知道集合中项目的计数。
在foreach循环中迭代的序列可能不支持索引或不知道这样一个概念,它只需要实现一个名为getEnumerator的方法,该方法返回一个对象,该对象至少具有IEnumerator接口,但不需要实现它。如果您知道您迭代的内容支持索引,并且您需要索引,那么我建议使用
可在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Foo { public iterator GetEnumerator() { return new iterator(); } public class iterator { public Bar Current { get{magic} } public bool MoveNext() { incantation } } } |
并非所有集合都有索引。例如,我可以将
如果我确实想遍历一个字典并跟踪一个索引,我就必须使用一个单独的变量,这个变量是我自己增加的。