Supprimer / Ajouter des éléments dans une liste en l'itérant
Tout d'abord, je sais que ce n'est pas possible de sortir de la boîte pour des raisons évidentes.
foreach(string item in myListOfStrings) {
myListOfStrings.Remove(item);
}
L'aide de l'extrait ci-dessus est l'une des choses les plus horribles que j'ai jamais vu. Alors, comment voulez-vous l'atteindre? Vous pourriez parcourir la liste vers l'arrière à l'aide de for
mais je n'aime pas cette solution.
Ce que je me pose est: y a t-il une méthode/extensions qui renvoie un IEnumerable partir de la liste actuelle, quelque chose comme un flottant copie? LINQ a de nombreuses méthodes d'extension qui font exactement cela, mais vous avez toujours à faire quelque chose avec elle, tels que le filtrage (où, prendre...).
J'ai hâte à quelque chose comme ceci:
foreach(string item in myListOfStrings.Shadow()) {
myListOfStrings.Remove(item);
}
où, comme .De l'ombre() est:
public static IEnumerable<T> Shadow<T>(this IEnumerable<T> source) {
return new IEnumerable<T>(source);
//or return source.Copy()
//or return source.TakeAll();
}
Exemple
foreach(ResponseFlags flag in responseFlagsList.Shadow()) {
switch(flag) {
case ResponseFlags.Case1:
...
case ResponseFlags.Case2:
...
}
...
this.InvokeSomeVoidEvent(flag)
responseFlagsList.Remove(flag);
}
Solution
C'est comment je l'ai résolu, et il fonctionne comme un charme:
public static IEnumerable<T> Shadow<T>(this IEnumerable<T> source) where T: new() {
foreach(T item in source)
yield return item;
}
C'est pas super rapide (évidemment), mais il est sûr et exactement ce que je voulais faire.
source d'informationauteur Atrotygma
Vous devez vous connecter pour publier un commentaire.
Suppression de plusieurs éléments de la liste 1 par 1 est un C# anti-modèle en raison de la façon dont les listes sont mises en œuvre.
Bien sûr, il peut être fait avec une boucle for (au lieu de foreach). Ou il peut être fait en faisant une copie de la liste. Mais ici, c'est pourquoi il ne doit pas être fait. Sur une liste de 100000 entiers aléatoires, cela prend 2500 ms sur ma machine:
et cela prend 1250 ms:
bien que ces deux prendre 5 et 2 ms respectivement:
C'est parce que lorsque vous supprimez un élément d'une liste, vous êtes en fait la suppression d'un tableauet ce est O(N) fois, que vous avez besoin de passer chaque élément après supprimés élément d'une position vers la gauche. En moyenne, ce sera de N/2 éléments.
Supprimer(élément) doit également trouver l'élément avant de l'enlever. Donc, Supprimer(élément) fait toujours prendre la N des étapes -
elementindex
étapes pour trouver l'élément,N - elementindex
étapes de l'enlever au total, N étapes.RemoveAt(index) n'a pas à trouver l'élément, mais il a encore de déplacer le sous-jacent de tableau, donc en moyenne, un RemoveAt est N/2 étapes.
Le résultat de fin est O(N^2) la complexité de toute façon, tant que vous êtes en train de retirer jusqu'à N éléments.
Au lieu de cela, vous devez utiliser Linq, ce qui va modifier l'ensemble de la liste en O(N) le temps, ou rouler votre propre, mais vous ne devez pas utiliser d'Éliminer (ou de RemoveAt) dans une boucle.
Pourquoi ne pas simplement faire:
Pour créer une copie de l'original et de l'utilisation de l'itération, puis retirer de l'existant.
Si vous avez vraiment besoin de votre méthode d'extension vous pourriez peut-être créer quelque chose de plus lisible pour l'utilisateur, telles que:
Qui est essentiellement la même que
.ToList()
.Appel:
foreach(string item in myListOfStrings.Shadow())
Vous n'avez pas d'extension LINQ des méthodes pour cela: vous pouvez créer une nouvelle liste explicitement, comme ceci:
Vous devez créer une copie de la liste d'origine lors de l'itération comme ci-dessous:
Votre exemple supprime tous les éléments de la chaîne, il est donc équivalente à:
Il est également équivaut à:
Mais je pense que vous êtes à la recherche d'un moyen de supprimer les éléments pour lesquels un prédicat qui est vrai, ce qui est
RemoveAll()
.De sorte que vous pourriez écrire, par exemple:
Ou d'utiliser tout autre prédicat.
Cependant, que les changements de la liste d'ORIGINE; Si vous voulez juste une copie de la liste avec certains éléments supprimés, vous pouvez simplement normal d'utilisation de Linq:
Ramasser sur la réponse de svinja je crois que le moyen le plus efficace de résoudre ce problème est de faire:
Il améliore la réponse en supprimant les sommes et les soustractions.