機能的なアプローチの場合、次のような先読み列挙子を実装できます。
IEnumerable<Item> collection = ...;
var lookahead = collection.Zip(collection.Skip(1), Tuple.Create);
列挙子は、各アイテムとそれに続くアイテムのタプルを繰り返し処理します。これは、コレクションの最後のアイテムを除外します。次に、クエリを実行するだけです。
var query = collection.Zip(collection.Skip(1), Tuple.Create)
.Where(tuple => tuple.Item1.Kind == null && tuple.Item2.Kind == null)
.Select(tuple => tuple.Item1);
残念ながら、これは非常に非効率的です。コレクションの長さを2回列挙しているため、非常に高額になる可能性があります。
このために独自の列挙子を作成して、コレクションを1回のパスでのみ実行することをお勧めします。
public static IEnumerable<TResult> LookAhead<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TSource, TResult> selector)
{
if (source == null) throw new ArugmentNullException("source");
if (selector == null) throw new ArugmentNullException("selector");
using (var enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
{
//empty
yield break;
}
var current = enumerator.Current;
while (enumerator.MoveNext())
{
var next = enumerator.Current;
yield return selector(current, next);
current = next;
}
}
}
次に、クエリは次のようになります。
var query = collection.LookAhead(Tuple.Create)
.Where(tuple => tuple.Item1.Kind == null && tuple.Item2.Kind == null)
.Select(tuple => tuple.Item1);