2012-06-29 10 views
14

Duplicar posible:
Getting odd/even part of a sequence with LINQ
How can I get every nth item from a List<T>?Seleccionar elementos pares/impares en IEnumerable <T>?

estoy usando HtmlAgilityPack y C# para analizar algo de 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> 

Básicamente, tengo estos elementos, cada uno en su propio objeto, dentro de un IEnumerable.

Hay una forma elegante de obtener cada elemento N/2 de la colección. Es decir, omita cada div con la clase .ruler?

Necesitaría iterar a través del conjunto resultante, así que o bien copio cada objeto encontrado en un nuevo IEnumerable o simplemente lo uso en línea en una función foreach.

Por ejemplo:

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

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

Qué opciones sería lo mejor, y cómo puedo lograr esto con elegancia?

+0

posibles duplicados: [Obteniendo parte impar/par de una secuencia con LINQ] (http://stackoverflow.com/questions/267033/getting-odd-even-part-of-a-sequence-with-linq), [ ¿Cómo puedo obtener cada enésimo elemento de una lista ?] (Http://stackoverflow.com/questions/682615/how-can-i-get-every-nth-item-from-a-listt) – mellamokb

Respuesta

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

La única cosa que no me gusta de esta solución es que requiere la iteración la secuencia dos veces si se necesita tanto las probabilidades y los iguala. Si por alguna razón se debe evitar esto, usted tiene que trabajar más duro:

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

A continuación, las probabilidades son aquellos elementos de groups donde el Key es false, y los iguala son aquellos elementos de groups donde el Key es true:

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

+1 I como la idea detrás del segundo enfoque. Sin embargo, tengo mucha curiosidad si esto es más rápido que la versión simple. No tiene que enumerar la colección original dos veces, pero con la creación de los objetos anónimos, la agrupación y la creación del diccionario, no sé si realmente vale la pena ... ¿Qué opina? –

+0

@PhilipDaubmeier: Creo que eso depende. Si solo 'Toma (1000)' del resultado, el primer enfoque podría ser incluso más rápido, al menos no importaría. Si tomara todo (es decir, usando 'Count()', 'foreach' o' ToList() '), el enfoque' Dictionary' podría ser significativamente más rápido. –

+0

Por cierto, el enfoque del diccionario causa una 'OutOfMemoryException' con un hugelist en una PC con 36GB ram, mientras que el double-'Where' siempre funcionaba y era realmente rápido si solo tomaba un subconjunto (fe' Take (1000) 'como mencionado anteriormente). –

3

se podía definir su propio método de extensión para este propósito:

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; 
     } 
    } 
} 
Cuestiones relacionadas