Is there a better way of calling LINQ Any + NOT All?

后端 未结 8 923
走了就别回头了
走了就别回头了 2021-02-18 14:46

I need to check if a sequence has any items satisfying some condition but at the same time NOT all items satisfying the same condition.

For example, for a sequence of 10

8条回答
  •  逝去的感伤
    2021-02-18 15:16

    If you wanted to define this as a method, you could take then approach Linq takes in defining both IEnumerable and IQueryable extension methods. This allows for the optimal approach to be taken automatically:

    public static bool SomeButNotAll(this IQueryable source, Expression> predicate)
    {
      if(source == null)
        throw new ArgumentNullException("source");
      if(predicate == null)
        throw new ArgumentNullException("predicate");
      return source.
        Select(predicate)
        .Distinct()
        .Take(2)
        .Count() == 2;
    }
    public static bool SomeButNotAll(this IEnumerable source, Func predicate)
    {
      if(source == null)
        throw new ArgumentNullException("source");
      if(predicate == null)
        throw new ArgumentNullException("predicate");
      using(var en = source.GetEnumerator())
        if(en.MoveNext())
        {
          bool first = predicate(en.Current);
          while(en.MoveNext())
            if(predicate(en.Current) != first)
              return true;
        }
      return false;
    }
    

    If you're using EntityFramework (or another provider that provides a CountAsync you can also provide an asynchronous version easily:

    public static async Task SomeButNotAllAsync(this IQueryable source, Expression> predicate, CancellationToken cancel)
    {
      if(source == null)
        throw new ArgumentNullException("source");
      if(predicate == null)
        throw new ArgumentNullException("predicate");
      cancel.ThrowIfCancellationRequested();
      return await source.
        Select(predicate)
        .Distinct()
        .Take(2)
        .CountAsync(cancel)
        .ConfigureAwait(false) == 2;
    }
    public static Task SomeButNotAllAsync(this IQueryable source, Expression> predicate)
    {
      return source.SomeButNotAllAsync(predicate, CancellationToken.None);
    }
    

提交回复
热议问题