2009-06-26 18 views
21

Sto verificando il codice nel riflettore, ma non ho ancora scoperto come può enumerare attraverso una raccolta al contrario?Come funziona IEnumerable <T>. Reverse?

Poiché non vi sono informazioni di conteggio e l'enumerazione inizia sempre dal "inizio" della raccolta, giusto?

È un inconveniente nel framework .NET? Il costo è più alto dell'enumerazione regolare?

+0

Non c'è IEnumerable . Metodo inverso che abbia mai visto (e MSDN sembra supportare questo)! – Noldorin

+8

Questo perché è un metodo di estensione: http://msdn.microsoft.it/it/us/library/bb358497.aspx –

+2

@Noldorin: Enumerable.Reverse è un metodo di estensione su IEunumerable

risposta

40

In breve, respinge tutto e quindi lo attraversa all'indietro. Non efficiente, ma poi, neanche OrderBy è da questa prospettiva.

In LINQ-to-Objects, ci sono operazioni di buffering (Reverse, OrderBy, GroupBy, ecc.) E operazioni di non buffering (Dove, Take, Skip, ecc.).


Come esempio di un non-buffering Reverse implementazione utilizzando IList<T>, prendere in considerazione:

public static IEnumerable<T> Reverse<T>(this IList<T> list) { 
    for (int i = list.Count - 1; i >= 0; i--) { 
     yield return list[i]; 
    } 
} 

Si noti che questo è ancora un po 'suscettibile di bug se si Mutate the lista, mentre l'iterazione è ... quindi non farlo ;-p

+0

Grazie Marc. Con il buffering, vuoi dire che copia l'intera collezione, come dice Levi? –

+3

Esattamente quello, sì. –

+0

Grazie Marc. Per curiosità, sai anche se si potrebbe fare una enumerazione migliore, con una nuova interfaccia? Ho sempre pensato che IEnumerable fosse buono (ed è), ma si sarebbe in grado di progettarne uno che funzionasse meglio anche in questi casi? –

6

Funziona copiando il sottostante IEnumerable <T> in una matrice, quindi eseguendo l'enumerazione su tale matrice all'indietro. Se il sottostante IEnumerable <T> implementa ICollection <T> (come T [], List <T>, ecc.), Il passaggio di copia viene saltato e l'enumeratore esegue semplicemente un'iterazione direttamente sulla raccolta sottostante.

Per ulteriori informazioni, consultare System.Linq.Buffer <TElement> in Reflector.

Modifica: la raccolta sottostante viene sempre copiata, anche se è un ICollection <TElement>. Ciò impedisce che le modifiche nella raccolta sottostante vengano propagate dal Buffer <TElement>.

+0

Sto guardando il buffer , e non riesco a vedere quando si ignora il passaggio di copia - cura di elaborare? –

+0

@Marc, @Levi: esegue ancora una copia, ma utilizza il metodo ICollection .CopyTo anziché enumerare la sequenza. – LukeH

3

carica tutti gli elementi in memoria e quindi li attraversa (indietro). questo è molto meno efficiente.

-3

Modifica: Opps, ha scritto il test sbagliato per il contrario, le mie scuse per la risposta sbagliata. Fa il buffer dopo aver corretto il test (usando enumerable restituito da Reverse())

Sembra che il metodo di estensione Reverse funzioni solo quando la raccolta è popolata. Durante l'utilizzo del rendimento restituito non fa nulla.

Si è rovinato il problema usando il reverse pensato che deve bufferizzare perché funzioni, trovato che non funziona con rendimento. Basta passarlo e non fare nulla. sotto è il mio codice di prova.

 [TestMethod] 
    public void loopTest() 
    { 
     var series = this.GetSeries(); 

     series.Reverse(); 

     foreach (var l in series) 
     { 
      Debug.WriteLine(l); 
     } 
    } 

    private IEnumerable<long> GetSeries() 
    { 
     var series = new List<long>() { 1, 2, 3, 4 }; 

     foreach (var entry in series) 
     { 
      Debug.WriteLine(entry); 

      yield return entry; 
     } 
    } 

inversa non chiamare la funzione GetSeries a tutti, tutti i colloqui di buffer in questo forum sembra dal nulla.

+1

Il metodo di estensione Reverse non inverte effettivamente la raccolta sottostante. Piuttosto, produce una nuova enumerabile che enumererà la raccolta in ordine inverso. La tua linea che assomiglia a 'serie.Reverse();' non ha effetto. Se cambi la linea in modo che assomigli a 'var reverse = series.Reverse();' e poi iterate su 'reverseed', tnen otterrai la risposta corretta. – wageoghe

+0

Grazie a wageoghe, per indicare il problema. – mamu

Problemi correlati