2009-06-22 12 views
19

Jaki jest preferowany sposób przenoszenia niektórych elementów (nie wszystkich) z jednej listy do drugiej.Jak przenieść elementy z listy na inną listę w języku C#?

Co robię jest następujący:

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

otherList.AddRange(selected); 

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

W interesie mający najszybszą najlepszy/kod istnieje, czy istnieje lepszy sposób?

+0

chciałbym przyjrzeć się metodą ForEach na listy, aby sobie z tym poradzić. Prawdopodobnie chcesz również standaryzować używając składni zapytania lub składni metody, a nie obu. –

Odpowiedz

13

bym spróbować @ odpowiedź Mehrdad, a może przetestować go przed tym jedną za ...

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

Proste! zaakceptowana odpowiedź. –

9

Proponuję:

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

To zdecydowanie jest szybszy od zaakceptowanej odpowiedzi 'ForEach' –

6

To jest bardzo złe wyniki mądry - to faktycznie wylicza zapytania n razy (dla n elementów w items). Byłoby lepiej, gdybyś zbudował (na przykład) HashSet<T> elementów do manipulowania.

Aby podać prosty przykład tylko z int wartości:

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

Nie jestem pewien, czy poprawnie widzę, jak kwerenda będzie wyliczyć n razy ... Czy to ze względu na użycie" wybranych "kwerendy zarówno w AddRange i RemoveAll ? W najgorszym przypadku, myślałem, że wyliczenie pójdzie tylko dwa razy ... –

+2

"selected" to IEnumerable <> zapytanie - * nie * kontener. "selected.Contains" wylicza to zapytanie przy każdym wywołaniu. –

+0

Oh! Teraz widzę. Masz rację. –

6

removeAll idzie koryta każdy element i wylicza wszystkie wartości wybranej listy za każdym razem. Będzie to trwać dłużej niż powinno ...

Co chciałbym zrobić, to umieścić warunek bezpośrednio w parametrze removeAll:

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

Jeśli to zrobisz i nie zmieniają reszty kodu byłoby duplikowanie kodu, co nie jest dobre. Chciałbym wykonać następujące czynności, aby tego uniknąć:

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

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

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

+1. Jest to najlepsza metoda (chyba że warunek Where jest dużo bardziej złożony niż sprawdzanie równości elementów). Tylko upewnij się, że nie zmieniasz kolekcji między wywołaniami metod. Możesz stracić elementy. –

+0

btw, nie możesz użyć 'var' z lambda (nawet jeśli naprawisz uszkodzoną składnię). –

+0

Myślę, że teraz jest naprawiony. Czy oprócz mojego brakującego średnika była jeszcze inna "zepsuta" składnia? –

1

Jak o partycji:

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]; 
Powiązane problemy