9

私はリストを持っています(簡略化)

[Kind]      [Name]
null        E
null        W
4           T
5           G
6           Q
null        L
null        V
7           K
2           Z
0           F

{E、L}-> Kind==nullと次のKind==nullのアイテムが必要です

増加しているIDが順番にあると仮定します。

これはLinqで可能ですか?

4

2 に答える 2

9

このような?

void Main()
{
    List<SomeClass> list = new List<SomeClass>() {
        new SomeClass() { Kind = null, Name = "E" },
        new SomeClass() { Kind = null, Name = "W" },
        new SomeClass() { Kind = 4, Name = "T" },
        new SomeClass() { Kind = 5, Name = "G" },
        ...
    };

    var query = list.Where ((s, i) =>
        !s.Kind.HasValue &&
        list.ElementAtOrDefault(i + 1) != null &&
        !list.ElementAt(i + 1).Kind.HasValue);
}

public class SomeClass
{
    public int? Kind { get; set; }
    public string Name { get; set; }
}

編集:@Jeff Marcadoのソリューションを盗んで、上記の使用法と同様の拡張メソッドを実装しますが、少しクリーンで、インデックスを処理しません。

public static IEnumerable<TSource> WhereWithLookahead<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, bool> predicate) where TSource : class
{
    using(var enumerator = source.GetEnumerator())
    {
        if (!enumerator.MoveNext())
        {
            //empty
            yield break;
        }

        var current = enumerator.Current;
        while (enumerator.MoveNext())
        {
            var next = enumerator.Current;

            if(predicate(current, next))
            {
                yield return current;
            }

            current = next;
        }

        if (predicate(current, null))
        {
            yield return current;
        }

    }
}

// Use:
var query2 = list.WhereWithLookahead((current, next) =>
    !current.Kind.HasValue &&
    (next != null) &&
    next.Kind.HasValue);
于 2012-06-30T19:15:48.240 に答える
5

機能的なアプローチの場合、次のような先読み列挙子を実装できます。

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);
于 2012-07-01T00:52:49.530 に答える