J'ai une foreach
boucle et j'ai besoin d'exécuter une logique lorsque le dernier élément est choisi dans le List
, par exemple:
foreach (Item result in Model.Results)
{
//if current result is the last item in Model.Results
//then do something in the code
}
Puis-je savoir quelle boucle est la dernière sans utiliser de boucle et de compteurs?
Réponses:
Si vous avez juste besoin de faire quelque chose avec le dernier élément (par opposition à quelque chose de différent avec le dernier élément, l'utilisation de LINQ vous aidera ici:
Si vous devez faire quelque chose de différent avec le dernier élément, vous aurez besoin de quelque chose comme:
Bien que vous deviez probablement écrire un comparateur personnalisé pour vous assurer que vous pouviez dire que l'article était le même que l'article retourné par
Last()
.Cette approche doit être utilisée avec prudence car il se
Last
pourrait bien qu'elle doive parcourir la collection. Bien que cela ne soit pas un problème pour les petites collections, s'il devient volumineux, cela peut avoir des implications sur les performances. Il échouera également si la liste contient des éléments en double. Dans ce cas, quelque chose comme ça peut être plus approprié:la source
var last = Model.Result[Model.Result.Count - 1];
plus rapidement que d'utiliserLast()
Que diriez-vous d'une bonne boucle à l'ancienne?
Ou en utilisant Linq et foreach:
la source
Model.Results
c'est le casIEnumerable
. Vous pouvez appelerCount()
avant la boucle mais cela peut provoquer l'itération complète de la séquence.L'utilisation
Last()
sur certains types passera en boucle dans toute la collection!Ce qui signifie que si vous faites un
foreach
appelLast()
et que vous avez bouclé deux fois! que vous aimeriez certainement éviter dans les grandes collections.La solution consiste alors à utiliser une
do while
boucle:Donc, à moins que le type de collection soit de type,
IList<T>
laLast()
fonction itérera à travers tous les éléments de collection.Tester
Si votre collection fournit un accès aléatoire (par exemple des outils
IList<T>
), vous pouvez également vérifier votre article comme suit.la source
using
déclaration? Je pensais que cela n'était nécessaire que si un objet gère les ressources du système d'exploitation, mais pas pour les structures de données gérées.Comme Chris le montre, Linq fonctionnera; utilisez simplement Last () pour obtenir une référence à la dernière dans l'énumérable, et tant que vous ne travaillez pas avec cette référence, faites votre code normal, mais si vous travaillez avec cette référence, faites votre chose supplémentaire. Son inconvénient est qu'il sera toujours de complexité O (N).
Vous pouvez à la place utiliser Count () (qui est O (1) si IEnumerable est également un ICollection; cela est vrai pour la plupart des IEnumerables intégrés courants), et hybrider votre foreach avec un compteur:
la source
la source
foreach
blocage. Comme ceci:var lastItem = objList.LastOrDeafault();
. Ensuite , à l'intérieur de laforeach
boucle , vous pouvez vérifier la façon suivante :f (item.Equals(lastItem)) { ... }
. Dans votre réponse originale, l'objList.LastOrDefault()
itération sur la collection à chaque itération "foreach" (la complexité polinomiale est impliquée ).Comme l'a souligné Shimmy, l'utilisation de Last () peut être un problème de performances, par exemple si votre collection est le résultat en direct d'une expression LINQ. Pour éviter plusieurs itérations, vous pouvez utiliser une méthode d'extension "ForEach" comme celle-ci:
La méthode d'extension ressemble à ceci (en bonus supplémentaire, elle vous indiquera également l'index et si vous regardez le premier élément):
la source
En améliorant encore la réponse de Daniel Wolf , vous pouvez vous empiler sur une autre
IEnumerable
pour éviter plusieurs itérations et lambdas tels que:L'implémentation de la méthode d'extension:
la source
foreach
, ce qui est une amélioration.L'implémentation de l'itérateur ne fournit pas cela. Votre collection peut être une
IList
qui est accessible via un index dans O (1). Dans ce cas, vous pouvez utiliser unefor
boucle normale :Si vous connaissez le nombre, mais ne pouvez pas y accéder via des indices (donc le résultat est un
ICollection
), vous pouvez vous compter en incrémentant uni
dans leforeach
corps du et en le comparant à la longueur.Tout cela n'est pas parfaitement élégant. La solution de Chris est peut-être la meilleure que j'ai vue jusqu'à présent.
la source
Qu'en est-il de l'approche peu plus simple.
la source
La meilleure approche serait probablement d'exécuter cette étape après la boucle: par exemple
Ou si vous devez faire quelque chose pour le dernier résultat
la source
La réponse acceptée ne fonctionnera pas pour les doublons de la collection. Si vous êtes défini sur le
foreach
, vous pouvez simplement ajouter vos propres variables d'indexation.la source
en utilisant Linq et foreach:
https://code.i-harness.com/en/q/7213ce
la source
".Last ()" n'a pas fonctionné pour moi, j'ai donc dû faire quelque chose comme ceci:
la source
En faisant quelques petits ajustements à l'excellent code de Jon Skeet, vous pouvez même le rendre plus intelligent en autorisant l'accès à l'élément précédent et suivant. Bien sûr, cela signifie que vous devrez lire à l'avance 1 élément dans la mise en œuvre. Pour des raisons de performances, l'élément précédent et l'élément suivant sont uniquement conservés pour l'élément d'itération en cours. Ça va comme ça:
la source
Comment convertir
foreach
pour réagir au dernier élément:la source
Il suffit de stocker la valeur précédente et de travailler avec elle dans la boucle. Ensuite, à la fin, la valeur «précédente» sera le dernier élément, vous permettant de le gérer différemment. Aucun comptage ou bibliothèque spéciale requise.
la source
Vous pouvez simplement utiliser une boucle for et il n'est pas nécessaire d'ajouter un supplément
if
à l'intérieur dufor
corps:Le
-1
dans l'for
état se charge de sauter le dernier élément.la source
Jon Skeet a créé un
SmartEnumerable<T>
type il y a quelque temps pour résoudre ce problème exact. Vous pouvez voir sa mise en œuvre ici:http://codeblog.jonskeet.uk/2007/07/27/smart-enumerations/
Pour télécharger: http://www.yoda.arachsys.com/csharp/miscutil/
la source
Pour faire quelque chose de plus pour chaque élément, sauf pour le dernier, une approche basée sur les fonctions peut être utilisée.
Cette approche présente des inconvénients apparents: moins de clarté de code pour les cas plus complexes. Appeler des délégués pourrait ne pas être très efficace. Le dépannage n'est peut-être pas assez facile. Le bon côté - le codage est amusant!
Cela dit, je suggérerais d'utiliser des boucles simples pour les cas triviaux, si vous savez que le décompte de votre collection n'est pas terriblement lent.
la source
Une autre façon, que je n'ai pas vue publiée, est d'utiliser une file d'attente. C'est analogue à un moyen d'implémenter une méthode SkipLast () sans itérer plus que nécessaire. De cette façon, vous pourrez également le faire sur un nombre illimité de derniers éléments.
Pour appeler cela, vous devez procéder comme suit:
la source
la source
Vous pouvez créer une méthode d'extension spécialement dédiée à cela:
et vous pouvez l'utiliser comme ceci:
la source
Sur la base de la réponse de @ Shimmy, j'ai créé une méthode d'extension qui est la solution que tout le monde veut. Il est simple, facile à utiliser et ne parcourt la collection qu'une seule fois.
Cela fonctionne sur tout
IEnumerable<T>
. L'utilisation ressemble à ceci:La sortie ressemble à:
De plus, vous pouvez en faire une
Select
méthode de style. Ensuite, réutilisez cette extension dans leForEach
. Ce code ressemble à ceci:la source
Nous pouvons vérifier le dernier élément en boucle.
la source
la source
Vous pouvez faire comme ça:
la source