2009-09-04 12 views
26

Mi piace molto Last() e lo userei sempre per List<T> s. Ma poiché sembra essere definito per IEnumerable<T>, suppongo che enumeri prima l'enumerazione - questo dovrebbe essere O (n) in opposizione a O (1) per l'indicizzazione diretta dell'ultimo elemento di uno List<T>.Qual è la prestazione del metodo di estensione Last() per l'elenco <T>?

I metodi di estensione standard (Linq) sono a conoscenza di questo?

L'STL in C++ ne è a conoscenza in virtù di un intero "albero di ereditarietà" per gli iteratori e quant'altro.

+0

Quale albero di ereditarietà per gli iteratori? C++ non ha i metodi di estensione in primo luogo, quindi 'end()' su 'vector' è semplicemente implementato in modo diverso da quello di' list', e tutto ciò che vuole lavorare con gli iteratori per uno deve essere un 'template 'su' Iterator' parametro di tipo. –

risposta

30

ho appena usato riflettore di esaminare il codice per ultimo e controlla per vedere se si tratta di un IList<T> primo ed esegue la O appropriata (1) chiamata:


EDIT:

Su consiglio del mio avvocato ho rimosso lo snippet di codice dal riflettore. Se vuoi vedere il codice da solo ti suggerisco di prendere Reflector e farlo da solo (che tutti dovrebbero già avere) o semplicemente di guardare nella cronologia delle revisioni di questo post (poiché non c'è nulla che io possa fare al riguardo)

(o addirittura guardare la risposta di Marco che chiaramente non ha la stessa squadra legale crepa proteggendolo)


in modo da avere il leggero sovraccarico di un cast, ma non l'enorme sovraccarico di enumerazione.

+0

Un problema che è stato evidenziato (e ora i commenti sono stati cancellati facendomi apparire un idiota delirante) è che chiunque lavori su un'implementazione del framework - come Mono - non può aver mai visto alcun codice che Microsoft ha scritto così almeno è scortese pubblicarlo in chiaro. Non sto avendo molta fortuna effettivamente a cercare di vedere che è in realtà * illegale * e sarei interessato a vedere una citazione che è. Vedi le regole qui http://www.mono-project.com/Contribuendo –

+8

Probabilmente è anche illegale pubblicare un'immagine delle ruote della mia sedia, perché qualcuno l'ha invitato. A volte penso che la gente impazzisca per i problemi di copyright. –

+0

Ho pubblicato una domanda su meta qui (http://meta.stackexchange.com/questions/20153/posting-code-from-reflector) che mi ha praticamente convinto che è * è * illegale. Come ho già detto, l'ho solo cancellato perché alcuni commenti (che ora sono stati cancellati) mi hanno suggerito di farlo. Ho pubblicato il codice da reflector prima e sono sicuro che lo farò di nuovo. Non mi guarderò alle spalle per il team SWAT del copyright di Microsoft, dal momento che direi che qualsiasi cosa per migliorare la comprensione e la fiducia in .NET avvantaggiano Microsoft comunque. –

7

Contiene un'ottimizzazione per tutto ciò che implementa IList<T> nel qual caso cerca solo l'articolo alla lunghezza -1.

Tenete a mente che la stragrande maggioranza delle cose che manderà nel implementerà IList<T>

List<int> 
int[] 

e così via ... tutto implementare IList<T>

Per coloro che non possono guardare il codice di conferma, è possibile confermare utilizzando osservazione:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Diagnostics; 

namespace ConsoleApplication4 { 
    class Program { 

     static void Profile(string description, int iterations, Action func) { 

      // clean up 
      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 
      GC.Collect(); 

      // warm up 
      func(); 

      var watch = Stopwatch.StartNew(); 
      for (int i = 0; i < iterations; i++) { 
       func(); 
      } 
      watch.Stop(); 
      Console.Write(description); 
      Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds); 
     } 

     static void Main(string[] args) { 
      int[] nums = Enumerable.Range(1, 1000000).ToArray(); 

      int a; 

      Profile("Raw performance", 100000,() => { a = nums[nums.Length - 1]; }); 
      Profile("With Last", 100000,() => { a = nums.Last(); }); 

      Console.ReadKey(); 
     } 


    } 
} 

uscita:

0.123.
 
Raw performance Time Elapsed 1 ms 
With Last Time Elapsed 31 ms 

Quindi è solo 30 volte più lento e mantiene quel profilo di prestazioni con qualsiasi lista di lunghezza, che non è nulla nel grande schema di cose.

+0

Solo un piccolo nitpick: 'HashSet ' non implementa 'IList '. – LukeH

+0

@Luke, grazie corretto che –

2

Per List<T> è O (1), ma per altri enumerabili può essere O (N).

21

Si può semplicemente utilizzare Ultimo con List<T> senza preoccuparsi :)

Enumerable.Last tenta di downcast l'istanza IEnumerable<T>-IList<T>. Se ciò è possibile, utilizza l'indicizzatore e la proprietà Count.

Ecco parte della realizzazione come Reflector lo vede:

IList<TSource> list = source as IList<TSource>; 
if (list != null) 
{ 
    int count = list.Count; 
    if (count > 0) 
    { 
     return list[count - 1]; 
    } 
} 
0

Risposta breve:

O (1).

Spiegazione:

E 'evidente che Ultima() per Lista utilizza Count() metodo di estensione.

Count() controlli tipo di raccolta in fase di esecuzione e usa Conte proprietà se è disponibile.

Count proprietà per la lista ha O (1) la complessità così è il Last) metodo di estensione (.

+0

'Last' * non * usa il metodo di estensione' Count', ma hai ragione che entrambi i metodi possono essere O (1) in determinate circostanze: 'Last' controlla se la collezione implementa' IList 'e se è così ottiene l'ultimo elemento per indice invece di enumerare; Il metodo 'Count' controlla se la collezione implementa' ICollection 'e in tal caso ottiene la proprietà' Count' piuttosto che enumerare. – LukeH

+0

Grazie a Luke, non avevo il 100% giusto. Ultimo utilizza il conteggio delle proprietà per IList e ha la complessità di O (1). Ho appena controllato il codice per Ultimo (questa raccolta, predicato) ed è O (N). Quello è pigro. –

+0

@ Konstantin: se si passa un predicato al metodo 'Last', allora si deve eseguire un'enumerazione O (n) della raccolta per determinare quali elementi corrispondono al predicato. – LukeH

Problemi correlati