2009-06-22 16 views
19

Qual è il modo preferibile per trasferire alcuni elementi (non tutti) da una lista a un'altra.Come posso spostare elementi da un elenco a un altro elenco in C#?

Quello che sto facendo è la seguente:

var selected = from item in items 
       where item.something > 10 
       select item; 

otherList.AddRange(selected); 

items.RemoveAll(item => selected.Contains(item)); 

Nell'interesse di avere il miglior codice più veloce/c'è, c'è un modo migliore?

+0

vorrei guardare utilizzando il metodo ForEach sulla lista per gestire questa situazione. Inoltre, probabilmente vuoi standardizzare usando la sintassi della query o la sintassi del metodo, non entrambi. –

risposta

13

mi piacerebbe provare @ risposta di Mehrdad, e forse prova contro anche questo ...

var selected = items.Where(item => item.Something > 10).ToList(); 
selected.ForEach(item => items.Remove(item)); 
otherList.AddRange(selected); 
+0

Semplice! risposta accettata –

9

suggerisco:

var selected = items.Where(item => item.Something > 10).ToList(); 
items = items.Except(selected).ToList(); 
otherList.AddRange(selected); 
+0

Questo è decisamente più veloce di 'ForEach' della risposta accettata –

6

che è abbastanza cattiva performance saggio - è in realtà una query enumera n volte (per n elementi in items). Sarebbe meglio se tu costruissi (per esempio) uno HashSet<T> degli oggetti da manipolare.

Per fare un esempio semplice, basta con int valori:

var items = new List<int> { 1, 2, 3, 4, 5, 6 }; 
    var otherList = new List<int>(); 
    var selected = new HashSet<int>(items.Where(
     item => item > 3)); 
    otherList.AddRange(selected); 
    items.RemoveAll(selected.Contains); 
+0

Non sono sicuro di vedere correttamente come la query enumera n volte ... È a causa dell'uso della query" selezionata "in AddRange e RemoveAll ? Nel peggiore dei casi, ho pensato che l'enumerazione sarebbe andata solo due volte ... –

+2

"selected" è una query IEnumerable <> - * not * a container. "selected.Contains" enumera questa query ogni volta che viene richiamata. –

+0

Oh! Ora vedo. Hai ragione. –

6

RemoveAll va depressione ogni elemento e elenca tutti i valori dell'elenco selezionato ogni volta. Questo richiederà più tempo di quanto dovrebbe ...

Quello che mi piacerebbe fare è mettere la condizione direttamente nel parametro RemoveAll:

items.RemoveAll(item => item.something > 10); 

Se si esegue questa operazione e di non modificare il resto del codice ci sarebbe la duplicazione del codice, che non è buona. Farei quanto segue per evitarlo:

Func<ItemType, bool> selectedCondition = (item => item.something > 10); 

otherList.AddRange(items.Where(selectedCondition)); 

items.RemoveAll(new Predicate<ItemType>(selectedCondition)); 
+0

+1. Questo è il metodo migliore (a meno che la condizione Where sia molto più complessa rispetto alla verifica dell'eguaglianza degli elementi). Assicurati di non modificare la raccolta tra le chiamate al metodo. Potresti perdere elementi. –

+0

btw, non puoi usare 'var' con un lambda (anche se correggi la sintassi rotta). –

+0

Penso che sia stato risolto ora. C'era qualche altra sintassi "rotta" oltre al mio punto e virgola mancante? –

1

Che ne dite di una partizione:

int[] items = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 
var partition = items.ToLookup(x => x > 5); 
var part1 = partition[true]; 
var part2 = partition[false]; 
Problemi correlati