Quelle est la meilleure façon de modifier une liste dans un "foreach" en boucle?
Une nouvelle fonctionnalité de C# /.NET 4.0 est que vous pouvez changer votre énumérables dans un foreach
sans exception. Paul Jackson entrée de blog de Un Intéressant Effet de bord de la Concurrence: la Suppression d'Éléments d'une Collection lors de l'Énumération pour plus d'informations sur ce changement.
Quelle est la meilleure façon de faire les choses suivantes?
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable)
{
item.Add(new item2)
}
}
Habituellement j'utilise un IList
comme un cache/tampon jusqu'à la fin de la foreach
, mais est-il meilleure façon de faire?
- Hmm.. Pouvez-vous nous indiquer à la documentation de ce changement? Enumerables ont toujours été immuable lorsque l'énumération sur la collection.
- C'est une variation sur le thème qui l'a poussé Steve McConnell conseiller ne jamais singe avec l'indice de boucle.
- Changer sur .NET 4.0 lovethedot.net/2009/03/...
- Merci pour le lien! Mais, je me demande, ont été vous demandez comment faire cela avec ou sans cette nouvelle fonctionnalité? Je devine que sans, puisque vous avez accepté ma réponse, mais je suis un peu confus.
- Je sais que je suis en train de déterrer un très vieux conversation ici, mais je serais extrêmement prudent avec cela. Seule la nouvelle concurrente collections sont modifiables dans foreach - tous les précédents types de collection, et j'imagine que la majorité des futurs types de collection trop, sera toujours immuable, tandis que l'énumération sur eux. Faisant un usage intensif de ce caprice serait un moyen efficace de vous enfermer dans l'utilisation simultanée de collections, parce que si vous souhaitez utiliser un autre collection à l'avenir tous vos excentrique boucles foreach allait se briser.
- Double Possible de C# - Ne faites pas le singe avec l'indice de boucle
- C'est cette question en demandant spécifiquement sur le simultanées collections? Ou est-il en posant une question plus générale et de mentionner que seulement pour le contraste?
- Le lien en question n'est plus valide. Est-t-il un jour?
InformationsquelleAutor Polo | 2009-04-17
Vous devez vous connecter pour publier un commentaire.
La collection utilisée dans le foreach est immuable. C'est très bien de par leur conception.
Comme il est dit sur MSDN:
Le post dans la lien fournis par Poko indique que cela est permis dans la nouvelle concurrente de collections.
Faire une copie de l'énumération, à l'aide d'un IEnumerable méthode d'extension dans ce cas, et de les énumérer sur elle. Ce serait ajouter une copie de chaque élément dans chaque intérieur énumérable à cette énumération.
Comme mentionné, mais avec un exemple de code:
ToArray()
) pour itérer sur la liste.Pour illustrer Nippysaurus réponse: Si vous allez à ajouter les nouveaux éléments à la liste et souhaitez traiter le nouvellement ajouté aussi des articles au cours de la même énumération, alors vous pouvez simplement utiliser pour boucle au lieu de foreach boucle, le problème est résolu 🙂
Pour praticable exemple:
Sortie de dernier exemple:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 3, 5, 7, 9,
Liste (15 points)
0
1
2
3
4
5
6
7
8
9
1
3
5
7
9
Voici comment vous pouvez le faire (rapide et sale de la solution. Si vous vraiment besoin de ce genre de comportement, vous devriez reconsidérer votre conception ou de remplacer tous les
IList<T>
membres et d'agrégation de la liste des sources):LINQ est très efficace pour jongler avec les collections.
Votre structure et le type de sont pas clair pour moi, mais je vais essayer de l'adapter à votre exemple, au meilleur de ma capacité.
À partir de votre code, il apparaît que, pour chaque élément, vous ajoutez à ce point tout de son propre "Énumérable" propriété. C'est très simple:
Un exemple, disons que nous voulons pour itérer une collection et de supprimer les éléments où une certaine condition est vraie. En évitant
foreach
, à l'aide de LINQ:Ajouter un élément en fonction de chaque élément existant? Pas de problème:
Vous ne pouvez pas changer le énumérable collection alors qu'il est en train d'être énumérés, de sorte que vous aurez à faire vos modifications avant ou après l'énumération.
La
for
boucle est une bonne alternative, mais si votreIEnumerable
collection ne pas mettre en œuvreICollection
, il n'est pas possible.Soit:
1) Copie de la collection premier. Énumérer les copiés de collecte et de changement de la collection d'origine lors de l'énumération. (@tvanfosson)
ou
2) Tenir une liste des modifications et de les valider après l'énumération.
La meilleure approche dans une perspective de performance est probablement d'utiliser un ou deux tableaux. Copie de la liste à un tableau, faire des opérations sur le tableau, puis créer une nouvelle liste à partir du tableau. Accéder à un élément de tableau est plus rapide que l'accès à un élément de la liste, et les conversions entre un
List<T>
et unT[]
pouvez utiliser un rapide "de copie en bloc" de l'opération, ce qui évite les frais généraux associés à l'accès à des éléments individuels.Par exemple, supposons que vous avez un
List<string>
et que vous souhaitez avoir toutes les chaînes dans la liste qui commence parT
être suivi par un élément de "Boo", tandis que chaque chaîne de caractères qui commence par "U" est entièrement supprimée. Une meilleure approche serait probablement quelque chose comme:Il aurait été utile si
List<T>
fourni une méthode pour créer une liste à partir d'une partie d'un tableau, mais je suis au courant d'aucune méthode efficace pour le faire. Encore, les opérations sur les tableaux sont assez rapide. À noter est le fait que l'ajout et la suppression d'éléments de la liste n'a pas besoin de "pousser" d'autres éléments; chaque article est écrit directement à son endroit approprié dans le tableau.Vous devriez vraiment utiliser
for()
au lieu deforeach()
dans ce cas.À ajouter à Timo réponse LINQ peut être utilisé comme:
J'ai écrit une seule étape facile, mais grâce à cela, les performances seront dégradées
Voici mon extrait de code:-