2009-06-22 9 views
19

Was ist der beste Weg, um einige Objekte (nicht alle) von einer Liste in eine andere zu übertragen.Wie verschiebe ich Elemente aus einer Liste in eine andere Liste in C#?

Was ich tue, ist die folgende:

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

otherList.AddRange(selected); 

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

Im Interesse den schnellsten/besten Code ist, gibt es einen besseren Weg?

+0

ich mit der ForEach-Methode auf Liste aussehen würde, dies zu umgehen. Wahrscheinlich möchten Sie auch die Verwendung der Abfragesyntax oder der Methodensyntax standardisieren, nicht beide. –

Antwort

13

I @ Mehrdad Antwort versuchen würde, und es vielleicht gegen diese testen ...

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

Einfach! akzeptierte Antwort. –

9

Ich schlage vor:

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

Dies ist definitiv schneller als die angenommene Antwort 'ForEach' –

6

Das weise ziemlich schlechte Leistung ist - es aufzählt tatsächlich eine Abfrage n-mal (für n Elemente in items). Es wäre besser, wenn Sie (zum Beispiel) einen HashSet<T> der zu manipulierenden Elemente erstellen würden.

Um ein einfaches Beispiel nur mit int Werte geben: zu

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

Ich bin nicht sicher, ob ich richtig sehe, wie die Abfrage n mal auflisten wird ... Ist es wegen der Verwendung der" ausgewählten "Abfrage in den AddRange und RemoveAll ? Im schlimmsten Fall dachte ich, die Aufzählung würde nur zweimal gehen ... –

+2

"ausgewählt" ist eine IEnumerable <> Abfrage - * nicht * ein Container. "selected.Contains" zählt diese Abfrage jedes Mal auf, wenn sie aufgerufen wird. –

+0

Oh! Ich sehe jetzt. Du hast recht. –

6

RemoveAll geht Trog jedes Element und zählt jedes Mal die Werte Ihrer ausgewählten Liste auf. Das wird länger dauern, als sollte es ...

Was ich tun würde, den Zustand direkt in den RemoveAll Parameter gesetzt wird:

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

Wenn Sie dies tun und nicht den Rest des Codes ändern es würde Code-Duplikation geben, was nicht gut ist. Ich würde folgende tun, um es zu vermeiden:

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

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

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

+1. Dies ist die beste Methode (es sei denn, die Where-Bedingung ist viel komplexer als das Überprüfen der Elementgleichheit). Stellen Sie nur sicher, dass Sie die Auflistung zwischen den Methodenaufrufen nicht ändern. Sie könnten Elemente verlieren. –

+0

BTW, Sie können 'var' nicht mit einem Lambda verwenden (auch wenn Sie die fehlerhafte Syntax reparieren). –

+0

Ich denke, es ist jetzt behoben. Gab es neben meinem fehlenden Semikolon noch eine andere "gebrochene" Syntax? –

1

Wie über eine Partition:

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]; 
Verwandte Themen