J'ai écrit ceci:
public static class EnumerableExtensions
{
public static int IndexOf<T>(this IEnumerable<T> obj, T value)
{
return obj
.Select((a, i) => (a.Equals(value)) ? i : -1)
.Max();
}
public static int IndexOf<T>(this IEnumerable<T> obj, T value
, IEqualityComparer<T> comparer)
{
return obj
.Select((a, i) => (comparer.Equals(a, value)) ? i : -1)
.Max();
}
}
Mais je ne sais pas si ça existe déjà, n'est-ce pas?
Max
approche est que a: elle continue de chercher, et b: elle renvoie le dernier index quand il y a des doublons (les gens s'attendent généralement au premier index)ToList()/FindIndex()
tour fonctionne le mieuxRéponses:
L'intérêt de faire sortir les choses en tant que IEnumerable est que vous puissiez parcourir paresseusement le contenu. En tant que tel, il n'y a pas vraiment de concept d'index. Ce que vous faites n'a vraiment pas beaucoup de sens pour un IEnumerable. Si vous avez besoin de quelque chose qui prend en charge l'accès par index, placez-le dans une liste ou une collection réelle.
la source
IEnumerable<>
. Je n'achète pas tout le dogme "tu ferais ça".IEnumerable
alorsEnumerable.ElementAt
n'existerait pas.IndexOf
est simplement l'inverse - tout argument contre cela doit s'appliquer également àElementAt
.Je remettrais en question la sagesse, mais peut-être:
(utiliser
EqualityComparer<T>.Default
pour émuler!=
si nécessaire) - mais vous devez regarder pour renvoyer -1 si non trouvé ... alors peut-être le faire le long du cheminla source
TakeWhile
est intelligent! Gardez à l'esprit que cela renvoieCount
si l'élément n'existe pas, ce qui est un écart par rapport au comportement standard.Je le mettrais en œuvre comme ceci:
la source
==
pourrait avoir besoin de travail?KVP<T, int?>
(nullable index)IList<T>
et si c'est le cas, reportez-vous à sa méthode IndexOf au cas où il aurait une optimisation spécifique au type.La façon dont je fais actuellement est un peu plus courte que celles déjà suggérées et, pour autant que je sache, donne le résultat souhaité:
C'est un peu maladroit, mais cela fait le travail et est assez concis.
la source
La meilleure façon de saisir la position est par
FindIndex
Cette fonction n'est disponible que pourList<>
Exemple
Si vous avez un énumérateur ou un tableau, utilisez cette méthode
ou
la source
Je pense que la meilleure option est de mettre en œuvre comme ceci:
Il ne créera pas non plus l'objet anonyme
la source
Un peu tard dans le jeu, je sais ... mais c'est ce que j'ai fait récemment. Il est légèrement différent du vôtre, mais permet au programmeur de dicter ce que l'opération d'égalité doit être (prédicat). Ce que je trouve très utile pour traiter différents types, car j'ai alors une manière générique de le faire quel que soit le type d'objet et
<T>
l'opérateur d'égalité intégré.Il a également une très très petite empreinte mémoire, et est très, très rapide / efficace ... si vous vous en souciez.
Au pire, vous l'ajouterez simplement à votre liste d'extensions.
Quoi qu'il en soit ... le voici.
Espérons que cela aide quelqu'un.
la source
GetEnumerator
etMoveNext
plutôt que juste unforeach
?foreach
appelleraDispose
l'énumérateur s'il implémenteIDisposable
. (Voir stackoverflow.com/questions/4982396/… ) Comme le code de cette réponse ne sait pas si le résultat de l'appelGetEnumerator
est ou n'est pas jetable, il devrait faire de même. À ce stade, je ne suis toujours pas sûr qu'il y ait un avantage en termes de performances, bien qu'il y ait eu une IL supplémentaire dont le but ne m'a pas sauté dessus!foreach
boucle, auquel cas pour le cas particulier deT
étant un type valeur, il peut enregistrer une opération box / unbox en utilisant la boucle while. Cependant, cela n'est pas confirmé par l'IL que j'ai obtenue à partir d'une version de votre réponse avecforeach
. Je pense cependant que l'élimination conditionnelle de l'itérateur est importante. Pourriez-vous modifier la réponse pour inclure cela?Quelques années plus tard, mais cela utilise Linq, retourne -1 si non trouvé, ne crée pas d'objets supplémentaires et devrait court-circuiter une fois trouvé [par opposition à une itération sur tout le IEnumerable]:
Où 'FirstOr' est:
la source
source.Where
andsource.DefaultIfEmpty
créera par exemple unIEnumerable
each.Je suis tombé sur cela aujourd'hui dans une recherche de réponses et j'ai pensé ajouter ma version à la liste (sans jeu de mots). Il utilise l'opérateur conditionnel nul de c # 6.0
J'ai fait des «courses des vieux chevaux» (tests) et pour les grandes collections (~ 100 000), dans le pire des cas, l'élément que vous voulez est à la fin, c'est 2x plus rapide que de le faire
ToList().FindIndex()
. Si l'élément que vous voulez est au milieu, il est ~ 4x plus rapide.Pour les collections plus petites (~ 10 000), il semble être légèrement plus rapide
Voici comment je l'ai testé https://gist.github.com/insulind/16310945247fcf13ba186a45734f254e
la source
En utilisant la réponse de @Marc Gravell, j'ai trouvé un moyen d'utiliser la méthode suivante:
afin d'obtenir -1 lorsque l'élément est introuvable:
Je suppose que cette méthode pourrait être à la fois la plus rapide et la plus simple. Cependant, je n'ai pas encore testé les performances.
la source
Une alternative à la recherche de l'index après coup consiste à encapsuler le Enumerable, un peu similaire à l'utilisation de la méthode Linq GroupBy ().
Ce qui donne un cas d'utilisation de:
la source
Cela peut devenir vraiment cool avec une extension (fonctionnant comme un proxy), par exemple:
Qui attribuera automatiquement des index à la collection accessible via ce
Index
propriété.Interface:
Extension personnalisée (probablement la plus utile pour travailler avec EF et DbContext):
la source