2008-10-26 86 views
15

有没有更好的方法来做到这一点?使用LINQ查询获取索引值的集合

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); 

即我正在寻找一个更有效或更优雅的方式来获得符合条件的项目的位置。

回答

28

您可以轻松地添加自己的扩展方法:

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++; 
    } 
} 

然后使用它:

string[] s = {"zero", "one", "two", "three", "four", "five"}; 
var x = s.IndexesWhere(t => t.StartsWith("t")); 
5

对我来说似乎很好。如果你只是使用的例子,以此来学习LINQ,忽略这个帖子

.Select((Value, Index) => new {Value, Index}) 
+0

谢谢 - 我不知道你可以这样做 - 我以为你必须重新分配。 – Guy 2008-10-26 02:07:23

+2

它被称为“投影初始值设定项” - 它基本上取表达式中的最后一个子表达式(它必须是一个字段或属性)并将其用于名称。所以你可以做x.GetFoo()。Bar和那个相当于Bar = x.GetFoo()。Bar。 – 2008-10-26 07:12:36

6

:你可能会改变选择保存几个字符。


我不清楚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); 
    } 
} 
+0

感谢您的回答。我同意这会更有效率。正如你猜测的那样,这是一个更复杂的东西的简化版本,在这种特殊情况下,LINQ需要“完成”。 – Guy 2008-10-26 05:23:34

1

这个怎么样?它与原始海报相似,但我首先选择索引,然后构建符合条件的集合。

var x = s.Select((a, i) => i).Where(i => s[i].StartsWith("t")); 

由于列表完全迭代了两次,这比其他答案的效率要低。

0

我和同事讨论了这个有趣的问题,起初我认为JonSkeet的解决方案很好,但是我的同事指出了一个问题,即如果函数是IEnumerable<T>的扩展,那么它可以用于集合实现的地方它。

使用数组,它可以安全地说与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(); 
} 

在这里我们希望List.ToArray将尊重为了使最后的操作...