2010-08-25 28 views

回答

23

就想通了自己...

IEnumerable<T>.Where()方法有一个重载,是以当前元素的索引 - 医生给你开。

(new []{1,2,3,4,5}).Where((elem, idx) => idx % 2 == 0); 

这将返回

{1, 3, 5} 

更新:为了掩饰我的两个用例和丹道的建议,我们也可以指定返回的第一个元素应该是什么:

var firstIdx = 1; 
var takeEvery = 2; 
var list = new []{1,2,3,4,5}; 

var newList = list 
    .Skip(firstIdx) 
    .Where((elem, idx) => idx % takeEvery == 0); 

...将返回

{2, 4} 
+2

我第一次看到索引在集合谓词bravo中非常稳定的用法,我不会想到这件事。 – 2010-08-25 16:21:56

+0

你可以定义一个扩展方法,它返回this.Where(...)使你的应用程序本身更清晰。 – Douglas 2010-08-25 16:22:27

+5

我可能会建议使用'idx + 1'来匹配“每N个元素”的描述;至少对我来说,这表明返回的第一个元素应该是第N个元素。因此'{1,2,3,4,5}' - to * me * - 中的每个第二个元素表示'{2,4}'(您的代码返回'{1,3,5}')。不过,也许这是主观的。 – 2010-08-25 16:23:13

8

要实现Cristi's suggestion

public static IEnumerable<T> Sample<T>(this IEnumerable<T> source, int interval) 
{ 
    // null check, out of range check go here 

    return source.Where((value, index) => (index + 1) % interval == 0); 
} 

用法:

var upToTen = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 

var evens = upToTen.Sample(2); 
var multiplesOfThree = upToTen.Sample(3); 
+0

你也可以跳过数组并使用'Enumerable.Range(1,10)'。 – 2010-08-25 17:34:18

+2

@Anthony:这只是一个例子,用于立即理解。我知道一些开发人员必须查找'Enumerable.Range'。 – 2010-08-25 18:27:31

0

虽然不是LINQ你还可以与yield创建一个扩展方法。

public static IEnumerable<T> EverySecondObject<T>(this IEnumerable<T> list) 
{ 
    using (var enumerator = list.GetEnumerator()) 
    { 
     while (true) 
     { 
      if (!enumerator.MoveNext()) 
       yield break; 
      if (enumerator.MoveNext()) 
       yield return enumerator.Current; 
      else 
       yield break; 
     } 
    } 
} 
+2

用''使用'把它包起来! ('IEnumerable'继承'IDisposable'。) – 2010-08-25 19:01:03

+0

@Dan:你的意思是IEnumerator。我以前从未意识到这一点? <挖掘一些旧代码/> – 2010-08-25 19:19:40

+0

是的,我的意思是'IEnumerator'。哎呦! (出于某种原因,我总是输入其中一个,意思是输入另一个。必须是肌肉记忆。) – 2010-08-25 19:26:59

相关问题