2016-11-02 13 views
15

Câu hỏi: được đưa ra IEnumerable<>, cách kiểm tra xem chuỗi nào chứa nhiều hơn x mục?Tối ưu hóa LINQ Đếm()> 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; 
} 

Vấn đề ở đây là gì Count() sẽ chạy chuỗi đầy đủ và đó là 1E6 + mục (ToList() cũng là ý tưởng tồi). Tôi cũng không được phép thay đổi mã người tiêu dùng (đó là một phương thức chấp nhận chuỗi hoàn chỉnh).

+1

gì về 'Any'? – Pikoh

+1

'Any()' chắc chắn sẽ ổn chứ? 'Count()' liệt kê toàn bộ bộ sưu tập không giống 'Any' xác định xem một chuỗi có chứa bất kỳ phần tử nào không. – Ric

+0

@Pikoh, bad của tôi, 'Any()' đang chạy chuỗi cho đến khi mục đầu tiên sẽ phù hợp với điều kiện 'Where()'. Có, 'Any()' sẽ làm cho trường hợp khi 'x = 1'. – Sinatr

Trả lời

18

Trong trường hợp lớntest bộ sưu tập (khi Count()đắt), bạn có thể thử một thủ thuật tiêu biểu:

if (test.Skip(1).Any()) 

Trong trường hợp chungtest.Count() > x thể được viết lại thành

if (test.Skip(x).Any()) 

Chỉnh sửa: bạn có thể muốn ẩn một thủ đoạn như vậy trong một phương pháp , nói 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; 
      } 
      } 
     } 
     } 
    } 
    } 

và do đó, mã của bạn sẽ được

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); 
+2

Điều này khá thông minh! – n8wrl

+0

Nếu bộ sưu tập xảy ra để có 1 mục tho điều này sẽ thất bại ... '.Skip (-1)' sẽ làm việc nhưng tôi không hiểu làm thế nào 'lừa' này hoạt động. – Phill

+0

@Phill: đó là hành vi mong đợi: mã cố gắng tối ưu hóa 'test.Count()> 1', hãy chú ý'> 'không'> = '. –