Hey Linq那里的专家,
我刚刚问了一个非常相似的问题,并且知道解决方案可能非常容易,但仍然发现自己无法围绕如何使用linq以最有效的方式完成这个相当简单的任务。
我的基本情况是我有一个值列表,例如:
Lst1:
a
a
b
b
c
b
a
c
a
我想创建一个新列表,它将保存Lst1中的所有索引,例如值=“a”。 所以,在这个例子中,我们将:
LstIndexes:
0
1
6
8
现在,我知道我可以用循环(我宁愿避免使用Linq)来做这件事,我甚至想通过以下方式找出如何使用Linq:
LstIndexes= Lst1.Select(Function(item As String, index As Integer) index) _
.Where(Function(index As Integer) Lst1(index) = "a").ToList
我对此的挑战是它在列表上迭代两次因此效率低下。
如何使用Linq以最有效的方式获得我的结果?
感谢!!!!
答案 0 :(得分:58)
首先,你的代码实际上并没有在列表上迭代两次,它只迭代一次。
那就是说,你的Select
实际上只是得到了所有索引的序列;使用Enumerable.Range
:
var result = Enumerable.Range(0, lst1.Count)
.Where(i => lst1[i] == "a")
.ToList();
理解为什么列表实际上没有被迭代两次将需要一些时间来习惯。我会尝试给出一个基本的解释。
您应该考虑大多数LINQ方法,例如Select和Where作为管道。每种方法都做了一些工作。在Select
的情况下,你给它一个方法,它基本上说,“每当有人问我下一个项目时,我首先会问我输入序列的项目,然后使用我必须的方法来转换它进入其他东西,然后将该项目交给任何使用我的人。“ Where
,或多或少,正在说,“每当有人问我一个项目时,我都会问我输入序列的项目,如果函数说它很好我会传递它,如果不是我会继续询问物品,直到我得到一件物品。“
因此,当你链接它们时,ToList
会询问第一个项目,它会转到Where
,因为它是第一个项目,Where
转到Select
并询问它的第一项,Select
进入列表询问它的第一项。然后该列表提供了它的第一个项目。 Select
然后将该项转换为需要吐出的内容(在本例中,只是int 0)并将其提供给Where
。 Where
接受该项并运行它的函数,该函数确定它是真的,因此向0
吐出ToList
,将其添加到列表中。那整件事情又发生了9次。这意味着Select
将最终要求列表中的每个项目完成一次,并且它会将每个结果直接提供给Where
,这会将“通过测试”的结果直接提供给ToList,将它们存储在列表中。所有LINQ方法都经过精心设计,只能迭代源序列一次(当它们被迭代一次时)。
请注意,虽然这对您来说似乎很复杂,但计算机实际上很容易完成所有这些操作。它实际上并不像最初看起来那么强大。
答案 1 :(得分:7)
这有效,但可以说不是很整洁。
var result = list1.Select((x, i) => new {x, i})
.Where(x => x.x == "a")
.Select(x => x.i);
答案 2 :(得分:1)
这个怎么样,对我来说效果很好。
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();
}