如何在单个步骤中获取列表中项目的索引?


193

如何在列表中查找项目的索引而不遍历该索引?

当前,这看起来不太好-在列表中两次搜索同一项目,只是为了获得索引:

var oProp = something;

int theThingIActuallyAmInterestedIn = myList.IndexOf(myList.Single(i => i.Prop == oProp));

Answers:




71

编辑:如果您使用a List<>并且需要索引,那么List.FindIndex确实是最好的方法。对于需要任何其他内容(例如,最重要的内容IEnumerable<>)的人,我将在此处保留此答案。

使用其重载Select在谓词中使用索引,因此您可以将列表转换为(索引,值)对:

var pair = myList.Select((Value, Index) => new { Value, Index })
                 .Single(p => p.Value.Prop == oProp);

然后:

Console.WriteLine("Index:{0}; Value: {1}", pair.Index, pair.Value);

或者,如果您想要索引并且在多个地方使用它,则可以轻松编写自己的扩展方法,就像一样Where,但是它不返回原始项目,而是返回与谓词匹配的那些项目的索引。


似乎他想要的只是索引。List <>。FindIndex(Predicate <>)是最好的方法。尽管问题标题可能会暗示其他问题,但OP的描述非常清楚,他只需要索引“ int theThingIActuallyAmInterestedIn”
Louis Ricci

1
@LastCoder:啊哈-错过了FindIndex。是的,我完全同意。
乔恩·斯基特

需要明确的是,“索引/值->单”方法是否比手动迭代两次“更好”(在Big-O方面意味着更快)?还是LINQ2Objects提供者足够聪明,可以优化其中一次迭代?(我假设Select和Single通常都是O(n)运算)
sara

1
@kai:我认为您基本上需要阅读LINQ的工作原理。太复杂了,无法在评论中进行详细说明。但是...这仅遍历源集合一次。LINQ设置了一个管道,该管道将输入序列延迟转换为另一个序列,然后该Single()操作对该序列进行迭代并找到与谓词匹配的单个项。有关更多详细信息,请阅读我的edulinq博客系列:codeblog.jonskeet.uk/category/edulinq
Jon Skeet

1
+1我需要这个解决方案。老板以为我很聪明。建议我仔细记录此内容,因为它使用了匿名类型,并且对该区域中的下一个编码器可能不清楚。
亚当·威尔斯

14

如果您不想使用LINQ,则:

int index;
for (int i = 0; i < myList.Count; i++)
{
    if (myList[i].Prop == oProp)
    {
       index = i;
       break;
    }
}

这样,您只迭代一次列表。


22
@KingKing没有人说过。
2013年

1
这与Linq相同FindIndex吗?
Coops '16

2
可能不是相同的代码,List到处都有一些整洁的优化。但是我很难相信他们可以在小于O(n)的范围内搜索无序列表,因此我想说它们在实践中可能真的很相似。
萨拉

6
  1. 查找列表中任何字符串值的索引的简单解决方案。

这是字符串列表的代码:

int indexOfValue = myList.FindIndex(a => a.Contains("insert value from list"));
  1. 查找列表中任何Integer值的索引的简单解决方案。

这是整数列表的代码:

    int indexOfNumber = myList.IndexOf(/*insert number from list*/);

2

这是IEnumerable的可复制/粘贴扩展方法

public static class EnumerableExtensions
{
    /// <summary>
    /// Searches for an element that matches the conditions defined by the specified predicate,
    /// and returns the zero-based index of the first occurrence within the entire <see cref="IEnumerable{T}"/>.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="predicate">The predicate.</param>
    /// <returns>
    /// The zero-based index of the first occurrence of an element that matches the conditions defined by <paramref name="predicate"/>, if found; otherwise it'll throw.
    /// </returns>
    public static int FindIndex<T>(this IEnumerable<T> list, Func<T, bool> predicate)
    {
        var idx = list.Select((value, index) => new {value, index}).Where(x => predicate(x.value)).Select(x => x.index).First();
        return idx;
    }
}

请享用。


2

如果有人想知道该Array版本,它会像这样:

int i = Array.FindIndex(yourArray, x => x == itemYouWant);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.