2009-06-22 12 views
19

Quel est le moyen préférable pour transférer certains éléments (pas tous) d'une liste à une autre.Comment déplacer des éléments d'une liste vers une autre liste en C#?

Ce que je fais est la suivante:

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

otherList.AddRange(selected); 

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

Dans l'intérêt d'avoir le plus rapide/meilleur code il y a, est-il une meilleure façon?

+0

je chercherais à l'aide de la méthode ForEach sur la liste pour gérer cela. En outre, vous souhaitez probablement standardiser l'utilisation de la syntaxe de la requête ou de la syntaxe de la méthode, pas les deux. –

Répondre

13

Je vais essayer @ la réponse de Mehrdad, et peut-être tester contre celui-ci aussi ...

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

Simple! réponse acceptée. –

9

Je propose:

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

Ceci est certainement plus rapide que la réponse acceptée 'ForEach' –

6

C'est sage tout à fait mauvaise performance - il en fait une fois énumère n de requête (pour n articles dans items). Il serait préférable que vous construisiez (par exemple) un HashSet<T> des éléments à manipuler.

Pour donner un exemple simple avec juste int valeurs:

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

Je ne suis pas sûr si je vois correctement comment la requête va énumérer n fois ... Est-ce dû à l'utilisation de la requête" selected "dans AddRange et RemoveAll ? Au pire, je pensais que l'énumération n'allait que deux fois ... –

+2

"selected" est une requête IEnumerable <> - * pas * un conteneur. "selected.Contains" énumère cette requête chaque fois qu'elle est invoquée. –

+0

Oh! Je vois maintenant. Tu as raison. –

6

RemoveAll va creux chaque élément et énumère toutes les valeurs de votre liste sélectionnée à chaque fois. Cela prendra plus longtemps que prévu ...

Ce que je ferais est mis l'état directement dans le paramètre RemoveAll:

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

Si vous faites cela et ne modifiez pas le reste de votre code il y aurait duplication de code, ce qui n'est pas bon. Je fais ce qui suit pour l'éviter:

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

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

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

+1. C'est la meilleure méthode (sauf si la condition Where est beaucoup plus complexe que la vérification de l'égalité des éléments). Assurez-vous simplement que vous ne modifiez pas la collection entre les appels de méthode. Vous pourriez perdre des éléments. –

+0

btw, vous ne pouvez pas utiliser 'var' avec un lambda (même si vous corrigez la syntaxe cassée). –

+0

Je pense que c'est corrigé maintenant. Y avait-il une autre syntaxe "cassée" en plus de mon point-virgule manquant? –

1

Que diriez-vous d'une 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]; 
Questions connexes