如何使用LINQ获取索引?[重复]

    技术2023-05-27  32

    本文翻译自:How to get index using LINQ? [duplicate]

    This question already has an answer here: 这个问题已经在这里有了答案:

    Get List<> element position in c# using LINQ 9 answers 使用LINQ 9答案 在C#中获取List <>元素位置 How to get the index of an element in an IEnumerable? 如何获取IEnumerable中元素的索引? 12 answers 12个答案

    Given a datasource like that: 给定这样的数据源:

    var c = new Car[] { new Car{ Color="Blue", Price=28000}, new Car{ Color="Red", Price=54000}, new Car{ Color="Pink", Price=9999}, // .. };

    How can I find the index of the first car satisfying a certain condition with LINQ? 如何使用LINQ找到满足特定条件的第一辆汽车的索引 ?

    EDIT: 编辑:

    I could think of something like this but it looks horrible: 我可以想到这样的东西,但是看起来很可怕:

    int firstItem = someItems.Select((item, index) => new { ItemName = item.Color, Position = index }).Where(i => i.ItemName == "purple") .First() .Position;

    Will it be the best to solve this with a plain old loop? 用一个简单的旧循环解决这个问题是最好的吗?


    #1楼

    参考:https://stackoom.com/question/AMyK/如何使用LINQ获取索引-重复


    #2楼

    I will make my contribution here... why? 我将在这里贡献自己的力量...为什么? just because :p Its a different implementation, based on the Any LINQ extension, and a delegate. 只是因为:p它是基于Any LINQ扩展和委托的不同实现。 Here it is: 这里是:

    public static class Extensions { public static int IndexOf<T>( this IEnumerable<T> list, Predicate<T> condition) { int i = -1; return list.Any(x => { i++; return condition(x); }) ? i : -1; } } void Main() { TestGetsFirstItem(); TestGetsLastItem(); TestGetsMinusOneOnNotFound(); TestGetsMiddleItem(); TestGetsMinusOneOnEmptyList(); } void TestGetsFirstItem() { // Arrange var list = new string[] { "a", "b", "c", "d" }; // Act int index = list.IndexOf(item => item.Equals("a")); // Assert if(index != 0) { throw new Exception("Index should be 0 but is: " + index); } "Test Successful".Dump(); } void TestGetsLastItem() { // Arrange var list = new string[] { "a", "b", "c", "d" }; // Act int index = list.IndexOf(item => item.Equals("d")); // Assert if(index != 3) { throw new Exception("Index should be 3 but is: " + index); } "Test Successful".Dump(); } void TestGetsMinusOneOnNotFound() { // Arrange var list = new string[] { "a", "b", "c", "d" }; // Act int index = list.IndexOf(item => item.Equals("e")); // Assert if(index != -1) { throw new Exception("Index should be -1 but is: " + index); } "Test Successful".Dump(); } void TestGetsMinusOneOnEmptyList() { // Arrange var list = new string[] { }; // Act int index = list.IndexOf(item => item.Equals("e")); // Assert if(index != -1) { throw new Exception("Index should be -1 but is: " + index); } "Test Successful".Dump(); } void TestGetsMiddleItem() { // Arrange var list = new string[] { "a", "b", "c", "d", "e" }; // Act int index = list.IndexOf(item => item.Equals("c")); // Assert if(index != 2) { throw new Exception("Index should be 2 but is: " + index); } "Test Successful".Dump(); }

    #3楼

    myCars.TakeWhile(car => !myCondition(car)).Count();

    It works! 有用! Think about it. 想一想。 The index of the first matching item equals the number of (not matching) item before it. 第一个匹配项的索引等于它前面(不匹配)项的数目。

    Story time 讲故事的时间

    I too dislike the horrible standard solution you already suggested in your question. 我也不太喜欢您在问题中已经提出的可怕标准解决方案 。 Like the accepted answer I went for a plain old loop although with a slight modification: 像已接受的答案一样,我做了一个简单的旧循环,尽管稍作修改:

    public static int FindIndex<T>(this IEnumerable<T> items, Predicate<T> predicate) { int index = 0; foreach (var item in items) { if (predicate(item)) break; index++; } return index; }

    Note that it will return the number of items instead of -1 when there is no match. 请注意,如果没有匹配项,它将返回项目数而不是-1 。 But let's ignore this minor annoyance for now. 但是,现在让我们忽略这种小麻烦。 In fact the horrible standard solution crashes in that case and I consider returning an index that is out-of-bounds superior . 实际上,在这种情况下, 可怕的标准解决方案崩溃了, 我考虑返回超出界限的索引 。

    What happens now is ReSharper telling me Loop can be converted into LINQ-expression . 现在发生的是ReSharper告诉我Loop可以转换为LINQ-expression 。 While most of the time the feature worsens readability, this time the result was awe-inspiring. 尽管大多数情况下该功能会降低可读性,但这次的结果却令人敬畏。 So Kudos to the JetBrains. 因此,对JetBrains表示敬意。

    Analysis 分析

    Pros 优点

    Concise 简洁 Combinable with other LINQ 与其他LINQ组合 Avoids new ing anonymous objects 避免new匿名对象 Only evaluates the enumerable until the predicate matches for the first time 仅评估可枚举,直到谓词首次匹配

    Therefore I consider it optimal in time and space while remaining readable. 因此,我认为它在时间和空间上都是最佳的,同时保持可读性。

    Cons 缺点

    Not quite obvious at first 起初不太明显 Does not return -1 when there is no match 没有匹配项时不返回-1

    Of course you can always hide it behind an extension method. 当然,您始终可以将其隐藏在扩展方法后面。 And what to do best when there is no match heavily depends on the context. 当没有匹配项时,最佳方法很大程度上取决于上下文。


    #4楼

    Here's an implementation of the highest-voted answer that returns -1 when the item is not found: 这是投票最高的答案的实现,未找到该项目时返回-1:

    public static int FindIndex<T>(this IEnumerable<T> items, Func<T, bool> predicate) { var itemsWithIndices = items.Select((item, index) => new { Item = item, Index = index }); var matchingIndices = from itemWithIndex in itemsWithIndices where predicate(itemWithIndex.Item) select (int?)itemWithIndex.Index; return matchingIndices.FirstOrDefault() ?? -1; }

    #5楼

    Simply do : 只需:

    int index = List.FindIndex(your condition);

    Eg 例如

    int index = cars.FindIndex(c => c.ID == 150);

    #6楼

    myCars.Select((v, i) => new {car = v, index = i}).First(myCondition).index;

    或稍短

    myCars.Select((car, index) => new {car, index}).First(myCondition).index;
    Processed: 0.017, SQL: 8