优化LINQ Count()> X.

Sin*_*atr 15 c# linq

问题:给定IEnumerable<>,如何检查哪些序列包含多个x项目?


MCVE:

static void Main(string[] args)
{
    var test = Test().Where(o => o > 2 && o < 6); // ToList()
    if (test.Count() > 1) // how to optimize this?
        foreach (var t in test) // consumer
            Console.WriteLine(t);
}

static IEnumerable<int> Test()
{
    for (int i = 0; i < 10; i++)
        yield return i;
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是什么Count()将运行完整序列和那些1E6+项目(ToList()也是坏主意).我也不被允许更改消费者代码(这是接受完整序列的方法).

Dmi*_*nko 18

在的情况下, test集合(当Count()昂贵的),你可以尝试典型的伎俩:

if (test.Skip(1).Any()) 
Run Code Online (Sandbox Code Playgroud)

一般情况下, test.Count() > x可以改写成

if (test.Skip(x).Any()) 
Run Code Online (Sandbox Code Playgroud)

编辑:你可能想在方法中隐藏这样的技巧,比如说:EnsureCount

  public static partial class EnumerableExtensions {
    public static IEnumerable<T> EnsureCount<T>(this IEnumerable<T> source, int count) {
      if (null == source)
        throw new ArgumentNullException("source");

      if (count <= 0)
        foreach (var item in source)
          yield return item;
      else {
        List<T> buffer = new List<T>(count);

        foreach (var item in source) {
          if (buffer == null)
            yield return item;
          else {
            buffer.Add(item);

            if (buffer.Count >= count) {
              foreach (var x in buffer)
                yield return x;

              buffer = null;
            }
          }
        }
      }
    }
  } 
Run Code Online (Sandbox Code Playgroud)

所以你的代码将是

  var test = Test()
    .Where(o => o > 2 && o < 6)
    .EnsureCount(2); // <- Count() > 1, so at least 2 items

  foreach (var t in test)
    Console.WriteLine(t); 
Run Code Online (Sandbox Code Playgroud)

  • 这非常聪明! (2认同)