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

Joh*_*tos 31 .net c# linq vb.net

嘿Linq专家在那里,

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

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

Lst1:
a
a
b
b
c
b
a
c
a
Run Code Online (Sandbox Code Playgroud)

我想创建一个新列表,它将保存Lst1中的所有索引,例如值="a".所以,在这个例子中,我们将:

LstIndexes:
0
1
6
8
Run Code Online (Sandbox Code Playgroud)

现在,我知道我可以用循环来做这个(我宁愿避免使用Linq),我甚至想出了如何用Linq以下面的方式做到这一点:

LstIndexes= Lst1.Select(Function(item As String, index As Integer) index) _
                .Where(Function(index As Integer) Lst1(index) = "a").ToList
Run Code Online (Sandbox Code Playgroud)

我对此的挑战是它在列表上迭代两次,因此效率低下.

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

谢谢!!!!

Ser*_*rvy 64

首先,您的代码实际上不会在列表上迭代两次,它只迭代一次.

也就是说,你Select真的只是得到了所有索引的序列; 这更容易完成Enumerable.Range:

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

理解为什么列表实际上没有被迭代两次将需要一些时间来习惯.我会试着给出一个基本的解释.

您应该考虑大多数LINQ方法,例如Select和Where作为管道.每种方法都做了一些工作.在Select你给它一个方法的情况下,它基本上说,"每当有人问我下一个项目时,我首先会问我输入序列的项目,然后使用我必须的方法将其转换成其他东西,并且然后把那个项目交给任何使用我的人." Where或多或少地说,"每当有人问我一件物品时,我都会问我输入序列的物品,如果功能说它好,我会把它传递给我,如果不是,我会继续要求物品直到我得到一个通过."

因此,当你链接他们时会发生的事情是ToList要求第一个项目,它会转到Where它的第一个项目,Where转到Select并询问它的第一个项目,Select转到列表以询问它的第一个项目.然后该列表提供了它的第一个项目. Select然后将该项转换为需要吐出的内容(在本例中,只是int 0)并将其赋予Where. Where获取该项并运行它的函数,该函数确定它是真的并因此吐出,0ToList其添加到列表中.那整件事情又发生了9次.这意味着Select最终会要求列表中的每个项目完成一次,并且它将直接将每个项目的结果提供给Where,它将把"传递测试"的结果直接提供给ToList,ToList将它们存储在列表中.所有LINQ方法都经过精心设计,只能迭代源序列一次(当它们被迭代一次时).

请注意,虽然这对您来说似乎很复杂,但计算机实际上很容易完成所有这些操作.它实际上并不像最初看起来那样具有性能密集程度.


Jim*_*son 7

这可行,但可以说不是很整洁.

var result = list1.Select((x, i) => new {x, i})
                  .Where(x => x.x == "a")
                  .Select(x => x.i);
Run Code Online (Sandbox Code Playgroud)