Bon, j'ai donc un énumérable et je souhaite en obtenir des valeurs distinctes.
En utilisant System.Linq
, il y a bien sûr une méthode d'extension appelée Distinct
. Dans le cas simple, il peut être utilisé sans paramètres, comme:
var distinctValues = myStringList.Distinct();
C'est bien, mais si j'ai une liste d'objets pour lesquels je dois spécifier l'égalité, la seule surcharge disponible est:
var distinctValues = myCustomerList.Distinct(someEqualityComparer);
L'argument du comparateur d'égalité doit être une instance de IEqualityComparer<T>
. Je peux le faire, bien sûr, mais c'est un peu bavard et, bien, grossier.
Ce à quoi je m'attendais, c'est une surcharge qui prendrait un lambda, disons un Func <T, T, bool>:
var distinctValues
= myCustomerList.Distinct((c1, c2) => c1.CustomerId == c2.CustomerId);
Quelqu'un sait-il si une telle extension existe, ou une solution de contournement équivalente? Ou est-ce que je manque quelque chose?
Sinon, existe-t-il un moyen de spécifier une ligne IEqualityComparer (embarrassez-moi)?
Mise à jour
J'ai trouvé une réponse d'Anders Hejlsberg à un message dans un forum MSDN sur ce sujet. Il dit:
Le problème que vous allez rencontrer est que lorsque deux objets sont comparables, ils doivent avoir la même valeur de retour GetHashCode (sinon la table de hachage utilisée en interne par Distinct ne fonctionnera pas correctement). Nous utilisons IEqualityComparer car il regroupe les implémentations compatibles de Equals et GetHashCode dans une seule interface.
Je suppose que cela a du sens ..
la source
.Distinct(new KeyEqualityComparer<Customer,string>(c1 => c1.CustomerId))
, et expliquer pourquoi GetHashCode () est important de travailler correctement.Réponses:
la source
DistinctBy
(ou mêmeDistinct
, car la signature sera unique).yield
instruction, donc la diffusion n'est techniquement pas possible. Merci pour votre réponse. Je vais l'utiliser lors du codage en C #. ;-)Il me semble que vous voulez
DistinctBy
de MoreLINQ . Vous pouvez alors écrire:Voici une version réduite de
DistinctBy
(pas de vérification de la nullité et pas d'option pour spécifier votre propre comparateur de clés):la source
yield
+ extra lib, foreach peut être réécrit commereturn source.Where(element => knownKeys.Add(keySelector(element)));
Pour conclure . Je pense que la plupart des gens qui sont venus ici comme moi veulent la solution la plus simple possible sans utiliser de bibliothèques et avec les meilleures performances possibles .
(Le groupe accepté par méthode pour moi, je pense, est une surpuissance en termes de performances.)
Voici une méthode d'extension simple utilisant l' interface IEqualityComparer qui fonctionne également pour les valeurs nulles.
Usage:
Code de méthode d'extension
la source
Non, il n'y a pas une telle surcharge de méthode d'extension pour cela. J'ai trouvé cela frustrant moi-même dans le passé et en tant que tel, j'écris habituellement un cours d'aide pour faire face à ce problème. Le but est de convertir un
Func<T,T,bool>
enIEqualityComparer<T,T>
.Exemple
Cela vous permet d'écrire ce qui suit
la source
IEqualityComparer<T>
partir d'une projection: stackoverflow.com/questions/188120/…Solution sténographique
la source
Cela fera ce que vous voulez mais je ne connais pas les performances:
Au moins, ce n'est pas verbeux.
la source
Voici une méthode d'extension simple qui fait ce dont j'ai besoin ...
C'est dommage qu'ils n'aient pas cuit une méthode distincte comme celle-ci dans le cadre, mais bon ho.
la source
x.Key
pourx.First()
changer la valeur de retour àIEnumerable<T>
Quelque chose que j'ai utilisé et qui a bien fonctionné pour moi.
la source
Toutes les solutions que j'ai vues ici reposent sur la sélection d'un domaine déjà comparable. Si l'on doit comparer d'une manière différente, cependant, cette solution semble fonctionner généralement, pour quelque chose comme:
la source
Prenez une autre voie:
La séquence renvoie des éléments distincts les compare par la propriété '_myCaustomerProperty'.
la source
Vous pouvez utiliser InlineComparer
Exemple d'utilisation :
Source: https://stackoverflow.com/a/5969691/206730
Utilisation d'IEqualityComparer pour Union
Puis-je spécifier mon comparateur de type explicite en ligne?
la source
Vous pouvez utiliser LambdaEqualityComparer:
la source
Une façon délicate de le faire est d'utiliser l'
Aggregate()
extension, en utilisant un dictionnaire comme accumulateur avec les valeurs de propriété de clé comme clés:Et une solution de style GroupBy utilise
ToLookup()
:la source
Dictionary<int, Customer>
place?Je suppose que vous avez un IEnumerable, et dans votre exemple de délégué, vous aimeriez que c1 et c2 se réfèrent à deux éléments dans cette liste?
Je crois que vous pourriez y parvenir avec une auto-jointure var distinctResults = de c1 dans ma liste, rejoignez c2 dans ma liste sur
la source
Si
Distinct()
ne produit pas de résultats uniques, essayez celui-ci:la source
Le package Microsoft System.Interactive a une version de Distinct qui prend un sélecteur de clés lambda. C'est en fait la même chose que la solution de Jon Skeet, mais il peut être utile pour les gens de savoir et de consulter le reste de la bibliothèque.
la source
Voici comment procéder:
Cette méthode vous permet de l'utiliser en spécifiant un paramètre comme
.MyDistinct(d => d.Name)
, mais elle vous permet également de spécifier une condition ayant comme deuxième paramètre comme ceci:NB Cela vous permettrait également de spécifier d'autres fonctions comme par exemple
.LastOrDefault(...)
.Si vous souhaitez exposer uniquement la condition, vous pouvez la rendre encore plus simple en l'implémentant comme:
Dans ce cas, la requête ressemblerait à ceci:
NB Ici, l'expression est plus simple, mais note
.MyDistinct2
utilise.FirstOrDefault(...)
implicitement.Remarque: Les exemples ci-dessus utilisent la classe de démonstration suivante
la source
IEnumerable
extension lambda:Usage:
la source