在C#中,一个位于List内部的对象如何知道它在列表中的索引位置?
在C#中,如果一个对象位于一个List中,它如何知道自己在List中的索引呢?这个问题的出现是因为枚举的概念与索引的概念是不同的,无法直接获取索引。然而,大多数集合都可以使用索引器和for循环结构进行遍历。以下是解决这个问题的方法:
1. 使用for循环:可以通过使用for循环来遍历List,并使用一个变量来跟踪对象在List中的索引。
for (int i = 0; i < myList.Count; i++) { // 通过i获取对象在List中的索引 }
2. 使用LINQ的Select方法:可以使用LINQ的Select方法将List中的对象与对应的索引组合在一起。这样可以在遍历过程中获取对象的索引。
var indexedItems = myList.Select((item, index) => new { Item = item, Index = index }); foreach (var indexedItem in indexedItems) { // 使用indexedItem.Index获取对象在List中的索引 }
通过以上两种方法,我们可以在遍历过程中获取对象在List中的索引。这样就解决了原问题中对象如何知道自己在List中的索引的问题。
在C#中,如果一个对象在一个列表中,它如何知道自己在列表中的索引呢?这个问题的出现是因为需要在遍历一个列表时,同时获取每个元素的索引。解决方法是使用LINQ的Select方法中的重载,该重载可以在遍历列表时返回元素的索引。
以下是解决该问题的代码示例:
foreach (var item in Model.Select((value, i) => new { i, value })) { var value = item.value; var index = item.i; }
这里使用了LINQ的Select方法,通过传入一个lambda表达式,返回一个包含元素索引和值的匿名对象。通过访问该对象的属性,可以获取元素的索引和值。
如果使用的是C# 7.0或更高版本,还可以使用ValueTuple来避免堆分配的开销:
foreach (var item in Model.Select((value, i) => ( value, i ))) { var value = item.value; var index = item.i; }
此外,还可以使用自动解构来消除item前缀:
foreach (var (value, i) in Model.Select((value, i) => ( value, i ))) { // 在此处直接访问value和i。 }
以上的解决方案适用于在Razor模板中使用,可以方便地获取每个元素的索引。需要注意的是,使用匿名对象会增加额外的内存开销。
这种解决方案使用LINQ的Select方法,该方法的第二个参数表示源元素的索引。关于这个重载的文档可以在这里找到。
有人可能会问,为什么这个解决方案被认为是一个好答案,为什么会有这么多赞(在撰写本文时有超过450个赞)?从我看来,这种方法比简单地增加一个计数器更难理解,不易于维护,占用更多内存,而且可能更慢。我有什么遗漏了吗?对此有人做过性能和内存使用的测试吗?
LINQ的Select方法(带有索引参数)在大多数C#程序员中已经很常见了。只有当你还不熟悉LINQ及其函数式编程风格时,才会感到困惑。
声明循环块内部的变量是低效的。它会导致内存地址的滥用,直到方法结束时都会保留这些变量。
通过使用LINQ的Select方法的重载,我们可以在遍历列表时获取每个元素的索引。这种方法可以提高代码的可读性和简洁性,并且适用于某些特定的场景。然而,需要注意匿名对象会增加额外的内存开销。如果性能和内存使用是重要的考虑因素,可以进行相关的测试和比较。
在C#中,如果一个对象在List中,它如何知道它在List中的索引?
C#7.0终于有了一个可以在foreach循环中获取索引的合理语法(即元组):
foreach (var (item, index) in collection.WithIndex()) { Debug.WriteLine($"{index}: {item}"); }
需要一个小的扩展方法:
using System.Collections.Generic; public static class EnumExtension { public static IEnumerable<(T item, int index)> WithIndex(this IEnumerable self) => self.Select((item, index) => (item, index)); }
这个答案被低估了,使用元组会更加简洁。
修改以处理空集合:
public static IEnumerable<(T item, int index)> WithIndex(this IEnumerable self) => self?.Select((item, index) => (item, index)) ?? new List<(T, int)>();
为了让习惯于其他语言的人更容易识别,可能将方法命名为Enumerated(并且也可以交换元组参数的顺序)。不过WithIndex本身已经很明显了。
对于空条件,你也可以使用
Enumerable.Empty<(T, int)>()
来代替创建一个空列表,这样效率更高。