Vous demandez donc ArgMinou ArgMax. C # n'a pas d'API intégrée pour ceux-ci.
Je cherchais un moyen propre et efficace (O (n) dans le temps) de le faire. Et je pense que j'en ai trouvé un:
La forme générale de ce modèle est:
var min = data.Select(x => (key(x), x)).Min().Item2;
^ ^ ^
the sorting key | take the associated original item
Min by key(.)
Surtout, en utilisant l'exemple de la question d'origine:
Pour C # 7.0 et supérieur qui prend en charge le tuple de valeur :
var youngest = people.Select(p => (p.DateOfBirth, p)).Min().Item2;
Pour la version C # antérieure à 7.0, le type anonyme peut être utilisé à la place:
var youngest = people.Select(p => new { ppl = p; age = p.DateOfBirth }).Min().ppl;
Ils travaillent parce que les deux tuple de valeur et le type anonyme ont par défaut sensées comparateurs: pour (x1, y1) et (x2, y2), il compare d' abord x1vs x2, puis y1vs y2. C'est pourquoi le intégré .Minpeut être utilisé sur ces types.
Et comme le type anonyme et le tuple de valeur sont tous deux des types de valeur, ils devraient être tous deux très efficaces.
REMARQUE
Dans mes ArgMinimplémentations ci-dessus, j'ai supposé DateOfBirthprendre le type DateTimepour plus de simplicité et de clarté. La question d'origine demande d'exclure ces entrées avec un DateOfBirthchamp nul :
Les valeurs Null DateOfBirth sont définies sur DateTime.MaxValue afin de les exclure de la considération Min (en supposant qu'au moins une a un DOB spécifié).
Il peut être réalisé avec un pré-filtrage
people.Where(p => p.DateOfBirth.HasValue)
C'est donc sans importance pour la question de la mise en œuvre de ArgMinou ArgMax.
NOTE 2
L'approche ci-dessus a une mise en garde: lorsque deux instances ont la même valeur minimale, l' Min()implémentation essaiera de comparer les instances en tant que bris d'égalité. Cependant, si la classe des instances n'est pas implémentée IComparable, une erreur d'exécution sera levée:
Au moins un objet doit implémenter IComparable
Heureusement, cela peut encore être résolu de manière assez nette. L'idée est d'associer un "ID" distanct à chaque entrée qui sert de bris d'égalité sans ambiguïté. Nous pouvons utiliser un ID incrémentiel pour chaque entrée. En utilisant toujours l'âge des gens comme exemple:
var youngest = Enumerable.Range(0, int.MaxValue)
.Zip(people, (idx, ppl) => (ppl.DateOfBirth, idx, ppl)).Min().Item3;