2009-03-23 17 views
27

Sto osservando un elenco generico per trovare gli elementi in base a un determinato parametro.Elenco generico FindAll() vs. foreach

In generale, quale sarebbe l'implementazione migliore e più veloce?
1. Looping attraverso ogni elemento della lista e salvare ogni partita ad un nuovo elenco e di ritorno che

foreach(string s in list) 
{ 
    if(s == "match") 
    { 
     newList.Add(s); 
    } 
} 

return newList; 

O
2. Utilizzando il metodo FindAll e passandolo un delegato.

newList = list.FindAll(delegate(string s){return s == "match";}); 

Non funzionano entrambi in ~ O (N)? Quale sarebbe la migliore pratica qui?

saluti, Jonathan

risposta

41

Si consiglia di utilizzare il metodo FindAll o il metodo LINQ equivalente. Inoltre, considera di usare la lambda più concisa invece del tuo delegato se puoi (richiede C# 3.0):

var list = new List<string>(); 
var newList = list.FindAll(s => s.Equals("match")); 
9

Vorrei utilizzare il FindAll method in questo caso, in quanto è più conciso, e IMO, ha facile leggibilità.

Hai ragione che stanno praticamente andando a sia esibirsi in O (n), anche se il foreach statementdovrebbe essereleggermente più veloce dato non deve eseguire un'invocazione delegato (delegati comportano un leggero overhead rispetto ai metodi di chiamata diretta).

devo sottolineare quanto insignificante questa differenza è, è più che probabile che mai andare a fare la differenza a meno che non si sta facendo una massiccia numero di operazioni su una massiccia lista .

Come sempre, provare per vedere dove sono i colli di bottiglia e agire in modo appropriato.

4

List.FindAll è O (n) e cercherà l'intera lista.

Se si desidera eseguire il proprio iteratore con foreach, si consiglia di utilizzare la dichiarazione di rendimento e restituire un oggetto IEnumerable se possibile. In questo modo, se si finisce per avere solo un elemento della collezione, sarà più veloce (dal momento che è possibile interrompere il chiamante senza esaurire l'intera raccolta).

In caso contrario, attenersi all'interfaccia BCL.

3

Qualsiasi differenza di perf sarà molto minore. Suggerirei FindAll per chiarezza, o, se possibile, Enumerable.Where. Preferisco utilizzare i metodi Enumerable perché consente una maggiore flessibilità nel refactoring del codice (non si prende una dipendenza da List<T>).

5

Jonathan,

Una buona risposta si può trovare a questo è nel capitolo 5 (considerazioni sulle prestazioni) di Linq To Action.

Misurano a per ogni ricerca eseguita circa 50 volte e viene visualizzato con foreach = 68ms per ciclo/List.FindAll = 62ms per ciclo. In realtà, probabilmente sarebbe nel tuo interesse semplicemente creare un test e vedere di persona.

2

Sì, entrambe le implementazioni sono O (n). Devono esaminare ogni elemento dell'elenco per trovare tutte le corrispondenze. In termini di leggibilità, preferirei anche FindAll. Per le considerazioni sulle prestazioni, consultare LINQ in Action (Ch 5.3). Se stai usando C# 3.0 potresti anche applicare un'espressione lambda. Ma questo è solo la ciliegina sulla torta:

var newList = aList.FindAll(s => s == "match"); 
1

Im con i Lambda

List<String> newList = list.FindAll(s => s.Equals("match")); 
0

A meno che il team di C# ha migliorato le prestazioni per LINQ e FindAll, il seguente articolo sembra suggerire che for e foreach supererebbe LINQ e FindAll sull'enumerazione degli oggetti: LINQ on Objects Performance.

Questo artiglio è stato datato marzo 2009, poco prima di questo post originariamente richiesto.