C# 使用LINQ查询获取索引值的集合
有更好的方法吗C# 使用LINQ查询获取索引值的集合,c#,.net,arrays,linq,indexof,C#,.net,Arrays,Linq,Indexof,有更好的方法吗 string[] s = {"zero", "one", "two", "three", "four", "five"}; var x = s .Select((a,i) => new {Value = a, Index = i}) .Where(b => b.Value.StartsWith("t")) .Select(c => c.Index); i、 e.我正在寻找一种更有效或更优雅的方法来获得符合标准的项目位置。对我来说似乎很好。您可以通过将“选择
string[] s = {"zero", "one", "two", "three", "four", "five"};
var x =
s
.Select((a,i) => new {Value = a, Index = i})
.Where(b => b.Value.StartsWith("t"))
.Select(c => c.Index);
i、 e.我正在寻找一种更有效或更优雅的方法来获得符合标准的项目位置。对我来说似乎很好。您可以通过将“选择”更改为:
.Select((Value, Index) => new {Value, Index})
如果你只是用这个例子来学习LINQ,请忽略这篇文章
我不清楚LINQ是否是实现这一点的最佳方式。下面的代码似乎更有效,因为不需要创建新的匿名类型。诚然,您的示例可能是人为设计的,并且该技术在不同的上下文中可能更有用,例如在数据结构中,它可以利用值索引,但下面的代码相当直截了当,可以理解(无需思考),并且可以说更有效
string[] s = {"zero", "one", "two", "three", "four", "five"};
List<int> matchingIndices = new List<int>();
for (int i = 0; i < s.Length; ++i)
{
if (s[i].StartWith("t"))
{
matchingIndices.Add(i);
}
}
string[]s={“零”、“一”、“二”、“三”、“四”、“五”};
List matchingIndices=新列表();
对于(int i=0;i
您可以轻松添加自己的扩展方法:
public static IEnumerable<int> IndexesWhere<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
int index=0;
foreach (T element in source)
{
if (predicate(element))
{
yield return index;
}
index++;
}
}
集合列表中还有FindIndex方法,您可以为其创建一个delete方法,该方法可以从集合中返回索引。您可以参考msdn中的以下链接。这个怎么样?它类似于原始海报,但我首先选择索引,然后构建一个符合标准的集合
var x = s.Select((a, i) => i).Where(i => s[i].StartsWith("t"));
这比其他一些答案的效率要低一些,因为列表被完全迭代了两次。我与一位同事讨论了这个有趣的问题,起初我认为JonSkeet的解决方案很好,但我的同事指出了一个问题,即如果函数是
IEnumerable
的扩展,然后可以在集合实现它的地方使用它
对于数组,可以肯定地说,使用
foreach
生成的顺序将得到尊重(即foreach
将从第一个迭代到最后一个),但对于其他集合(列表、词典等),foreach
不一定反映“条目顺序”。然而,它的功能是存在的,它可能会产生误导
最后,我得到了与tvanfosson的答案类似的结果,但作为阵列的一种扩展方法:
public static int[] GetIndexes<T>(this T[]source, Func<T, bool> predicate)
{
List<int> matchingIndexes = new List<int>();
for (int i = 0; i < source.Length; ++i)
{
if (predicate(source[i]))
{
matchingIndexes.Add(i);
}
}
return matchingIndexes.ToArray();
}
公共静态int[]GetIndexes(此T[]源,Func谓词)
{
列表匹配索引=新列表();
对于(int i=0;i
这是希望
列表。ToArray
将尊重上一次操作的顺序…谢谢-我不知道你能做到这一点-我认为你必须重新分配。它被称为“投影初始值设定项”-它基本上接受表达式中最后一个子表达式(必须是字段或属性)并将其用作名称。所以你可以做x.GetFoo().Bar,这相当于Bar=x.GetFoo().Bar。谢谢你的回答。我同意这样会更有效率。正如您所猜测的,这是一个更复杂的简化版本,在这种特殊情况下,必须在LINQ中“完成”。而确切的代码只有在您使用列表而不是任意IEnumerable时才起作用。否则,您必须使用foreach和一个单独的局部变量。“但是函数存在,并且可能会产生误导。”-但对于使用索引的任何其他LINQ方法,例如.Select((项,索引)也是如此=>
。我认为只要你理解你得到了什么,Jon的函数就不一定有什么问题。@Rup从那以后,我在LINQ和IEnumerable接口方面积累了更多的经验。我同意如果你知道你在做什么,并且定义了函数,就不会有意外。一个潜在的危险是e从使用AsParallel
生成的IEnumerable中获取索引。这些索引将反映集合的生成状态,但再次生成几乎可以保证得到不同的结果。索引将引用不存在的内容。在团队工作中(或稍后重用该函数),如果这种行为不清楚,你会有麻烦的。不过,我仍然认为,除非你修改集合,否则顺序不太可能改变,除非对结构有意义,否则你不应该使用索引。但我没有考虑使用AsParallel-neat,谢谢。
public static int[] GetIndexes<T>(this T[]source, Func<T, bool> predicate)
{
List<int> matchingIndexes = new List<int>();
for (int i = 0; i < source.Length; ++i)
{
if (predicate(source[i]))
{
matchingIndexes.Add(i);
}
}
return matchingIndexes.ToArray();
}