LINQ中的隐式索引或生成索引

时间:2016-02-04 10:33:54

标签: c# indexing ienumerable

我最近遇到过一些情况,它让我想知道是否有任何方法可以获得内部索引,或者如果没有,在使用LINQ时有效地生成索引。

考虑以下情况:

List<int> list = new List() { 7, 4, 5, 1, 7, 8 };

在C#中,如果我们要使用LINQ在上面的数组上返回索引“7”,我们不能简单地使用IndexOf / LastIndexOf - 因为它只会返回第一个/最后一个结果。

这不起作用:

var result = list.Where(x => x == 7).Select(y => list.IndexOf(y));

然而,我们有几种解决方法。

例如,有一种方法可以做到这一点(我通常这样做):

int index = 0;
var result = from x in list
        let indexNow = index++
        where x == 7
        select indexNow;

它将使用let。

引入附加参数indexNow

另一种方式:

var result = Enumerable.Range(0, list.Count).Where(x => list.ElementAt(x) == 7);

它将使用Enumerable.Range生成另一组项目并从中选择结果。

现在,我想知道是否有其他更简单的方法,例如:

  1. 如果有任何(内置)方式获取IEnumerable的内部索引而不用let或
  2. 声明某些内容
  3. 使用Enumerable.Range以外的其他东西生成IEnumerable的索引(也许是新的东西?我不太熟悉怎么做),或者
  4. 其他任何可以缩短代码但仍然获得IEnumerable索引的内容。

1 个答案:

答案 0 :(得分:2)

来自IEnumerable.Select with indexHow to get index using LINQ?,依此类推:IEnumerable<T>.Select()有一个overload that provides an index

使用此功能,您可以:

  1. 将项目转换为匿名类型(或Tuple<int, T>,如果要将其公开给其他方法,匿名类型是本地的),其中包含索引和值。
  2. 根据您要查找的值过滤这些结果。
  3. 仅投影索引。
  4. 所以代码看起来像这样:

    var result = list.Select((v, i) => new { Index = i, Value = v })
                     .Where(i => i.Value == 7)
                     .Select(i => i.Index);
    

    现在result将包含一个包含所有索引的枚举。

    请注意,这仅适用于保证插入顺序并提供数字索引器的源集合类型,例如List<T>。当您将其用于Dictionary<TKey, TValue>HashSet<T>时,生成的索引将无法用于索引字典。