C# 使用 Linq 从列表中获取所有匹配值的索引

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13055391/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 01:30:13  来源:igfitidea点击:

Get indexes of all matching values from list using Linq

c#.netvb.netlinq

提问by John Bustos

Hey Linq experts out there,

嘿,那里的 Linq 专家,

I just asked a very similar question and know the solution is probably SUPER easy, but still find myself not being able to wrap my head around how to do this fairly simple task in the most efficient manner using linq.

我只是问了一个非常相似的问题,并且知道解决方案可能非常简单,但仍然发现自己无法理解如何使用 linq 以最有效的方式完成这项相当简单的任务。

My basic scenario is that I have a list of values, for example, say:

我的基本情况是我有一个值列表,例如,说:

Lst1:
a
a
b
b
c
b
a
c
a

And I want to create a new list that will hold all the indexes from Lst1 where, say, the value = "a". So, in this example, we would have:

我想创建一个新列表,该列表将包含 Lst1 中的所有索引,例如,值 =“a”。所以,在这个例子中,我们将有:

LstIndexes:
0
1
6
8

Now, I know I can do this with Loops (which I would rather avoid in favor of Linq) and I even figured out how to do this with Linq in the following way:

现在,我知道我可以用 Loops 做到这一点(我宁愿避免使用 Linq),我什至想出了如何用 Linq 做到这一点的方法如下:

LstIndexes= Lst1.Select(Function(item As String, index As Integer) index) _
                .Where(Function(index As Integer) Lst1(index) = "a").ToList

My challenge with this is that it iterates over the list twice and is therefore inefficient.

我对此的挑战是它对列表进行了两次迭代,因此效率低下。

How can I get my result in the most efficient way using Linq?

如何使用 Linq 以最有效的方式获得结果?

Thanks!!!!

谢谢!!!!

采纳答案by Servy

First off, your code doesn't actually iterate over the list twice, it only iterates it once.

首先,您的代码实际上并没有在列表上迭代两次,它只迭代一次。

That said, your Selectis really just getting a sequence of all of the indexes; that is more easily done with Enumerable.Range:

也就是说,您Select实际上只是获得了所有索引的序列;这更容易完成Enumerable.Range

var result = Enumerable.Range(0, lst1.Count)
             .Where(i => lst1[i] == "a")
             .ToList();

Understanding why the list isn't actually iterated twice will take some getting used to. I'll try to give a basic explanation.

理解为什么列表实际上没有迭代两次需要一些时间来适应。我会尽量给出一个基本的解释。

You should think of most of the LINQ methods, such as Select and Where as a pipeline. Each method does some tiny bit of work. In the case of Selectyou give it a method, and it essentially says, "Whenever someone asks me for my next item I'll first ask my input sequence for an item, then use the method I have to convert it into something else, and then give that item to whoever is using me." Where, more or less, is saying, "whenever someone asks me for an item I'll ask my input sequence for an item, if the function say it's good I'll pass it on, if not I'll keep asking for items until I get one that passes."

您应该将大多数 LINQ 方法(例如 Select 和 Where)视为管道。每种方法都做了一些微小的工作。在Select你给它一个方法的情况下,它本质上是说,“每当有人问我下一个项目时,我会首先询问我的输入序列中的一个项目,然后使用我必须将其转换为其他内容的方法,并且然后把那个东西交给使用我的人。” Where,或多或少是在说,“每当有人向我要一个项目时,我就会向我的输入序列询问一个项目,如果函数说它很好,我会传递它,如果不是,我会一直要求项目,直到我得到一个通过的。”

So when you chain them what happens is ToListasks for the first item, it goes to Whereto as it for it's first item, Wheregoes to Selectand asks it for it's first item, Selectgoes to the list to ask it for its first item. The list then provides it's first item. Selectthen transforms that item into what it needs to spit out (in this case, just the int 0) and gives it to Where. Wheretakes that item and runs it's function which determine's that it's true and so spits out 0to ToList, which adds it to the list. That whole thing then happens 9 more times. This means that Selectwill end up asking for each item from the list exactly once, and it will feed each of its results directly to Where, which will feed the results that "pass the test" directly to ToList, which stores them in a list. All of the LINQ methods are carefully designed to only ever iterate the source sequence once (when they are iterated once).

因此,当您将它们链接起来时,发生的事情是ToList请求第一个项目,它转到Where第一个项目,Where转到Select并询问它的第一个项目,Select转到列表询问它的第一个项目。该列表然后提供它的第一项。 Select然后将该项目转换为它需要吐出的内容(在这种情况下,只是 int 0)并将其提供给Where. Where获取该项目并运行它的函数,该函数确定它是真的,因此吐出0ToList,将其添加到列表中。然后整个事情又发生了 9 次。这意味着Select最终会要求列表中的每个项目恰好一次,并将其每个结果直接提供给Where,它将“通过测试”的结果直接提供给 ToList,后者将它们存储在一个列表中。所有 LINQ 方法都经过精心设计,只迭代一次源序列(当它们迭代一次时)。

Note that, while this seems complicated at first to you, it's actually pretty easy for the computer to do all of this. It's not actually as performance intensive as it may seem at first.

请注意,虽然一开始对您来说这似乎很复杂,但实际上计算机可以很容易地完成所有这些工作。它实际上并不像最初看起来那样密集。

回答by luis_laurent

How about this one, it works pretty fine for me.

这个怎么样,对我来说效果很好。

   static void Main(string[] args)
    {
        List<char> Lst1 = new List<char>();
        Lst1.Add('a'); 
        Lst1.Add('a');   
        Lst1.Add('b');   
        Lst1.Add('b');   
        Lst1.Add('c');   
        Lst1.Add('b');   
        Lst1.Add('a');   
        Lst1.Add('c');
        Lst1.Add('a');

        var result = Lst1.Select((c, i) => new { character = c, index = i })
                         .Where(list => list.character == 'a')
                         .ToList();
    }

回答by Jim Johnson

This works, but arguably not as neat.

这有效,但可以说没有那么整洁。

var result = list1.Select((x, i) => new {x, i})
                  .Where(x => x.x == "a")
                  .Select(x => x.i);