private IEnumerable<string> Tables
{
get
{
yield return "Foo";
yield return "Bar";
}
}
Disons que je veux les itérer et écrire quelque chose comme le traitement #n de #m.
Existe-t-il un moyen de connaître la valeur de m sans itérer avant mon itération principale?
J'espère que je me suis bien fait comprendre.
c#
.net
ienumerable
sebagomez
la source
la source
La
System.Linq.Enumerable.Count
méthode d'extension onIEnumerable<T>
a l'implémentation suivante:Il essaie donc de convertir en
ICollection<T>
, qui a uneCount
propriété, et l'utilise si possible. Sinon, il itère.Donc, votre meilleur pari est d'utiliser la
Count()
méthode d'extension sur votreIEnumerable<T>
objet, car vous obtiendrez ainsi les meilleures performances possibles.la source
ICollection<T>
premier.T
surIEnumerator<T> enumerator = source.GetEnumerator()
, simplement vous pouvez le faire:IEnumerator enumerator = source.GetEnumerator()
et devrait fonctionner!IEnumerable<T>
hérite,IDisposable
ce qui permet à l'using
instruction de le supprimer automatiquement.IEnumerable
ne fait pas. Donc, si vous appelez dans lesGetEnumerator
deux sens, vous devriez terminer avecvar d = e as IDisposable; if (d != null) d.Dispose();
Il suffit d'ajouter quelques informations supplémentaires:
L'
Count()
extension n'itère pas toujours. Considérez Linq à Sql, où le nombre va à la base de données, mais au lieu de ramener toutes les lignes, il émet laCount()
commande Sql et renvoie ce résultat à la place.De plus, le compilateur (ou runtime) est suffisamment intelligent pour appeler la
Count()
méthode objets s'il en a une. Ce n'est donc pas comme d'autres intervenants le disent, étant complètement ignorant et itérant toujours pour compter les éléments.Dans de nombreux cas où le programmeur vérifie simplement
if( enumerable.Count != 0 )
à l'aide de laAny()
méthode d'extension, commeif( enumerable.Any() )
c'est beaucoup plus efficace avec l'évaluation paresseuse de linq car il peut court-circuiter une fois qu'il peut déterminer qu'il y a des éléments. C'est aussi plus lisiblela source
.Count
propriété car elle sait toujours que c'est sa taille. Lors d'une requête,collection.Count
il n'y a pas de calcul supplémentaire, il renvoie simplement le nombre déjà connu. Pareil pourArray.length
autant que je sache. Cependant,.Any()
obtient l'énumérateur de la source à l'aide deusing (IEnumerator<TSource> enumerator = source.GetEnumerator())
et renvoie true s'il le peutenumerator.MoveNext()
. Pour les collectionsif(collection.Count > 0)
:, les tableaux:if(array.length > 0)
et sur les énumérateurs le fontif(collection.Any())
.IQueryably<T>
en un,IEnumerable<T>
il n'émettra pas de compte sql. Quand j'ai écrit cela, Linq to Sql était nouveau; Je pense que je poussais juste à utiliserAny()
car pour les énumérables, les collections et sql c'était beaucoup plus efficace et lisible (en général). Merci d'avoir amélioré la réponse.Un de mes amis a une série de billets de blog qui illustrent pourquoi vous ne pouvez pas faire cela. Il crée une fonction qui retourne un IEnumerable où chaque itération retourne le nombre premier suivant, jusqu'à
ulong.MaxValue
, et l'élément suivant n'est pas calculé jusqu'à ce que vous le demandiez. Question rapide et pop: combien d'articles sont retournés?Voici les articles, mais ils sont assez longs:
la source
EnumerableFeatures
objet) n'obligerait pas les enquêteurs à faire quelque chose de difficile, mais être capable de poser de telles questions (ainsi que d'autres comme «Pouvez-vous promettre de retourner toujours la même séquence d'éléments "," Pouvez-vous être exposé en toute sécurité à du code qui ne devrait pas altérer votre collection sous-jacente ", etc.) serait très utile.set yield options
déclaration ou quelque chose de similaire pour la soutenir. S'il est bien conçu, unIEnhancedEnumerator
pourrait rendre des choses comme LINQ beaucoup plus utilisables en éliminant beaucoup de "défensifs"ToArray
ou d'ToList
appels, en particulier ...Enumerable.Concat
sont utilisées pour combiner une grande collection qui en sait beaucoup sur elle-même avec une petite qui ne le sait pas.IEnumerable ne peut pas compter sans itérer.
Dans des circonstances "normales", il serait possible pour les classes implémentant IEnumerable ou IEnumerable <T>, telles que List <T>, d'implémenter la méthode Count en renvoyant la propriété List <T> .Count. Toutefois, la méthode Count n'est pas réellement une méthode définie sur l'interface IEnumerable <T> ou IEnumerable. (Le seul qui est, en fait, est GetEnumerator.) Et cela signifie qu'une implémentation spécifique à la classe ne peut pas être fournie pour cela.
Au contraire, Count c'est une méthode d'extension, définie sur la classe statique Enumerable. Cela signifie qu'il peut être appelé sur n'importe quelle instance d'une classe dérivée IEnumerable <T>, quelle que soit l'implémentation de cette classe. Mais cela signifie également qu'il est implémenté en un seul endroit, externe à l'une de ces classes. Ce qui bien sûr signifie qu'il doit être implémenté d'une manière complètement indépendante des internes de ces classes. La seule façon de faire le comptage est via l'itération.
la source
Vous pouvez également effectuer les opérations suivantes:
la source
Non, pas en général. Un point dans l'utilisation des énumérables est que l'ensemble réel d'objets dans l'énumération n'est pas connu (à l'avance, ou même pas du tout).
la source
Vous pouvez utiliser System.Linq.
Vous obtiendrez le résultat «2».
la source
Au-delà de votre question immédiate (à laquelle une réponse négative complète a été donnée), si vous cherchez à signaler les progrès tout en traitant un énumérable, vous voudrez peut-être consulter mon article de blog Rapporter les progrès pendant les requêtes Linq .
Il vous permet de faire ceci:
la source
J'ai utilisé cette méthode à l'intérieur d'une méthode pour vérifier le
IEnumberable
contenu transmisÀ l'intérieur d'une méthode comme celle-ci:
la source
bool hasContents = false; if (iEnum != null) foreach (object ob in iEnum) { hasContents = true; ... your code per ob ... }
.Cela dépend de la version de .Net et de l'implémentation de votre objet IEnumerable. Microsoft a corrigé la méthode IEnumerable.Count pour vérifier l'implémentation et utilise ICollection.Count ou ICollection <TSource> .Count, voir les détails ici https://connect.microsoft.com/VisualStudio/feedback/details/454130
Et ci-dessous se trouve le MSIL d'Ildasm pour System.Core, dans lequel réside System.Linq.
la source
Voici une excellente discussion sur l' évaluation paresseuse et l' exécution différée . Fondamentalement, vous devez matérialiser la liste pour obtenir cette valeur.
la source
Le résultat de la fonction IEnumerable.Count () peut être incorrect. Voici un échantillon très simple à tester:
Le résultat doit être (7,7,3,3) mais le résultat réel est (7,7,3,17)
la source
La meilleure façon que j'ai trouvée est de compter en la convertissant en liste.
la source
Je suggère d'appeler ToList. Oui, vous faites l'énumération tôt, mais vous avez toujours accès à votre liste d'articles.
la source
Il ne peut pas donner les meilleures performances, mais vous pouvez utiliser LINQ pour compter les éléments dans un IEnumerable:
la source
Je pense que la façon la plus simple de le faire
Référence: system.linq.enumerable
la source
J'utilise
IEnum<string>.ToArray<string>().Length
et ça marche bien.la source
IEnum<string>.Count();
"?J'utilise un tel code, si j'ai une liste de chaînes:
la source