C# LINQ 查找值的数组索引
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13291788/
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
LINQ to find array indexes of a value
提问by Dan Dinu
Assuming I have the following string array:
假设我有以下字符串数组:
string[] str = new string[] {"max", "min", "avg", "max", "avg", "min"}
Is it possbile to use LINQ to get a list of indexes that match one string?
是否可以使用 LINQ 来获取与一个字符串匹配的索引列表?
As an example, I would like to search for the string "avg" and get a list containing
例如,我想搜索字符串“avg”并获得一个包含
2, 4
2、4
meaning that "avg" can be found at str[2] and str[4].
这意味着可以在 str[2] 和 str[4] 处找到“avg”。
采纳答案by recursive
.Selecthas a seldom-used overload that produces an index. You can use it like this:
.Select有一个很少使用的重载,产生一个索引。你可以这样使用它:
str.Select((s, i) => new {i, s})
.Where(t => t.s == "avg")
.Select(t => t.i)
.ToList()
The result will be a list containing 2 and 4.
结果将是一个包含 2 和 4 的列表。
回答by dasblinkenlight
You can do it like this:
你可以这样做:
str.Select((v,i) => new {Index = i, Value = v}) // Pair up values and indexes
.Where(p => p.Value == "avg") // Do the filtering
.Select(p => p.Index); // Keep the index and drop the value
The key step is using the overload of Selectthat supplies the current index to your functor.
关键步骤是使用为您的函子提供当前索引的重载Select。
回答by Tim Schmelter
You can use the overload of Enumerable.Selectthat passes the index and then use Enumerable.Whereon an anonymous type:
您可以使用Enumerable.Select传递索引的重载,然后Enumerable.Where在匿名类型上使用:
List<int> result = str.Select((s, index) => new { s, index })
.Where(x => x.s== "avg")
.Select(x => x.index)
.ToList();
If you just want to find the first/last index, you have also the builtin methods List.IndexOfand List.LastIndexOf:
如果您只想找到第一个/最后一个索引,您还有内置方法List.IndexOf和List.LastIndexOf:
int firstIndex = str.IndexOf("avg");
int lastIndex = str.LastIndexOf("avg");
(or you can use this overloadthat take a start index to specify the start position)
(或者您可以使用此重载以开始索引来指定开始位置)
回答by Servy
While you could use a combination of Selectand Where, this is likely a good candidate for making your own function:
虽然你可以使用的组合Select和Where,这可能是一个很好的候选人为使自己的功能:
public static IEnumerable<int> Indexes<T>(IEnumerable<T> source, T itemToFind)
{
if (source == null)
throw new ArgumentNullException("source");
int i = 0;
foreach (T item in source)
{
if (object.Equals(itemToFind, item))
{
yield return i;
}
i++;
}
}
回答by Mikl X
You need a combined select and where operator, comparing to accepted answer this will be cheaper, since won't require intermediate objects:
您需要一个组合 select 和 where 运算符,与接受的答案相比,这将更便宜,因为不需要中间对象:
public static IEnumerable<TResult> SelectWhere<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, bool> filter, Func<TSource, int, TResult> selector)
{
int index = -1;
foreach (var s in source)
{
checked{ ++index; }
if (filter(s))
yield return selector(s, index);
}
}
回答by BrainCoder
First off, your code doesn't actually iterate over the list twice, it only iterates it once.
首先,您的代码实际上并没有在列表上迭代两次,它只迭代一次。
That said, your Select is 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, str.Count)
.Where(i => str[i] == "avg")
.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 Select you 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 的情况下,你给它一个方法,它本质上说,“每当有人问我下一个项目时,我会首先询问我的输入序列中的一个项目,然后使用我必须将它转换成其他东西的方法,然后把那个东西交给使用我的人。” 哪里,或多或少是说,“每当有人问我要一个项目时,我会问我的输入序列要一个项目,如果函数说它很好,我会传递它,如果不是,我会继续要求项目直到我得到一个通过。”
So when you chain them what happens is ToList asks for the first item, it goes to Where to as it for it's first item, Where goes to Select and asks it for it's first item, Select goes to the list to ask it for its first item. The list then provides it's first item. Select then transforms that item into what it needs to spit out (in this case, just the int 0) and gives it to Where. Where takes that item and runs it's function which determine's that it's true and so spits out 0 to ToList, which adds it to the list. That whole thing then happens 9 more times. This means that Select will 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 to 作为它的第一项,Where 转到 Select 并要求它的第一项,Select 转到列表要求它的第一项物品。该列表然后提供它的第一项。Select 然后将该项目转换为它需要吐出的内容(在本例中,只是 int 0)并将其提供给 Where。Where 获取该项目并运行它的函数,该函数确定它为真,因此将 0 吐出到 ToList,后者将其添加到列表中。然后整个事情又发生了 9 次。这意味着 Select 最终将只从列表中请求每个项目一次,并将其每个结果直接提供给 Where,然后将“通过测试”的结果直接提供给 ToList,后者将它们存储在列表中.
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.
请注意,虽然一开始对您来说这似乎很复杂,但实际上计算机可以很容易地完成所有这些工作。它实际上并不像最初看起来那样密集。

