2012-06-29 5 views
14

thể trùng lặp:
Getting odd/even part of a sequence with LINQ
How can I get every nth item from a List<T>?Chọn các phần tử chẵn/lẻ trong IEnumerable <T>?

Tôi đang sử dụng HtmlAgilityPack và C# để phân tích một số HTML.

<div id="post-8266"> 
<div class="ruler"> </div> 
<div id="post-8266"> 
<div class="ruler"> </div> 
<div id="post-8266"> 
<div class="ruler"> </div> 
<div id="post-8266"> 
<div class="ruler"> </div> 

Về cơ bản, tôi có những yếu tố này, mỗi trong đối tượng của riêng mình, bên trong một IEnumerable.

Có cách nào thanh lịch để lấy từng phần tử N/2 trong bộ sưu tập không. Có nghĩa là, bỏ qua từng div với lớp .ruler?

Tôi cần phải lặp qua tập hợp kết quả, do đó, hoặc là tôi sao chép từng đối tượng tìm thấy vào một IEnumerable mới hoặc chỉ sử dụng nó trong một hàm foreach.

Ví dụ:

//Copying resulting set to new IEnumerable<T>: 
var odds = elements.SelectOdds(); 

//Using it inline for my usage: 
foreach (var x in elements.SelectOdds()) 
{ 
} 

Những tùy chọn sẽ là tốt nhất, và làm thế nào tôi có thể đạt được điều này tao nhã?

+0

có thể trùng lặp: [Lấy lẻ/thậm chí một phần của chuỗi với LINQ] (http://stackoverflow.com/questions/267033/getting-odd-even-part-of-a-sequence-with-linq), [ Làm thế nào tôi có thể nhận được mọi mục thứ n từ Danh sách ?] (Http://stackoverflow.com/questions/682615/how-can-i-get-every-nth-item-from-a-listt) – mellamokb

Trả lời

27
var odds = sequence.Where((item, index) => index % 2 != 0); 
var evens = sequence.Where((item, index) => index % 2 == 0); 

Điều duy nhất tôi không thích về giải pháp này là nó yêu cầu lặp lại chuỗi hai lần nếu bạn cần cả tỷ lệ cược và số lần xuất hiện. Nếu vì một số lý do bạn phải tránh điều này, bạn sẽ phải làm việc chăm chỉ hơn:

var groups = sequence.Select((item, index) => new { Item = item, Index = index }) 
        .GroupBy(x => x.Index % 2 == 0) 
        .ToDictionary(g => g.Key, g => g); 

Sau đó, tỷ lệ cược là những yếu tố của groups nơi Keyfalse, và lại những sự kiện là những yếu tố của groups nơi Keytrue:

var odds = groups[false]; 
var evens = groups[true]; 
+1

+1 I như ý tưởng đằng sau phương pháp thứ hai. Tuy nhiên, tôi thực sự tò mò nếu điều này là nhanh hơn so với phiên bản đơn giản. Bạn không cần phải liệt kê bộ sưu tập gốc hai lần, nhưng với việc tạo ra các đối tượng đã được nặc danh, nhóm và tạo từ điển, tôi không biết liệu điều này có thực sự trả hết hay không ... Bạn nghĩ sao? –

+0

@PhilipDaubmeier: Tôi nghĩ điều đó phụ thuộc. Nếu bạn chỉ có 'Take (1000)' từ kết quả thì cách tiếp cận đầu tiên có thể nhanh hơn, ít nhất nó cũng không thành vấn đề. Nếu bạn dùng tất cả (f.e. bằng cách sử dụng 'Count()', 'foreach' hoặc' ToList() '), cách tiếp cận' Dictionary' có thể nhanh hơn đáng kể. –

+0

Bằng cách này, cách tiếp cận từ điển gây ra một 'OutOfMemoryException' với một hugelist trên PC với 36GB ram trong khi double-'Where' làm việc luôn luôn và thực sự nhanh chóng nếu bạn chỉ có một tập hợp con (fe' Take (1000) ' đã đề cập ở trên). –

3

bạn chỉ có thể xác định phương pháp khuyến nông của riêng bạn cho mục đích này:

public static class LinqExtensions 
{ 
    public static IEnumerable<T> SelectOdds<T>(this IEnumerable<T> enumerable) 
    { 
     bool odd = false; 

     foreach (var item in enumerable) 
     { 
      if (odd) 
       yield return item; 

      odd = !odd; 
     } 
    } 
}