1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections.Generic;
6 
7 namespace System.Linq
8 {
9     public static partial class Enumerable
10     {
Min(this IEnumerable<int> source)11         public static int Min(this IEnumerable<int> source)
12         {
13             if (source == null)
14             {
15                 throw Error.ArgumentNull(nameof(source));
16             }
17 
18             int value;
19             using (IEnumerator<int> e = source.GetEnumerator())
20             {
21                 if (!e.MoveNext())
22                 {
23                     throw Error.NoElements();
24                 }
25 
26                 value = e.Current;
27                 while (e.MoveNext())
28                 {
29                     int x = e.Current;
30                     if (x < value)
31                     {
32                         value = x;
33                     }
34                 }
35             }
36 
37             return value;
38         }
39 
Min(this IEnumerable<int?> source)40         public static int? Min(this IEnumerable<int?> source)
41         {
42             if (source == null)
43             {
44                 throw Error.ArgumentNull(nameof(source));
45             }
46 
47             int? value = null;
48             using (IEnumerator<int?> e = source.GetEnumerator())
49             {
50                 // Start off knowing that we've a non-null value (or exit here, knowing we don't)
51                 // so we don't have to keep testing for nullity.
52                 do
53                 {
54                     if (!e.MoveNext())
55                     {
56                         return value;
57                     }
58 
59                     value = e.Current;
60                 }
61                 while (!value.HasValue);
62 
63                 // Keep hold of the wrapped value, and do comparisons on that, rather than
64                 // using the lifted operation each time.
65                 int valueVal = value.GetValueOrDefault();
66                 while (e.MoveNext())
67                 {
68                     int? cur = e.Current;
69                     int x = cur.GetValueOrDefault();
70 
71                     // Do not replace & with &&. The branch prediction cost outweighs the extra operation
72                     // unless nulls either never happen or always happen.
73                     if (cur.HasValue & x < valueVal)
74                     {
75                         valueVal = x;
76                         value = cur;
77                     }
78                 }
79             }
80 
81             return value;
82         }
83 
Min(this IEnumerable<long> source)84         public static long Min(this IEnumerable<long> source)
85         {
86             if (source == null)
87             {
88                 throw Error.ArgumentNull(nameof(source));
89             }
90 
91             long value;
92             using (IEnumerator<long> e = source.GetEnumerator())
93             {
94                 if (!e.MoveNext())
95                 {
96                     throw Error.NoElements();
97                 }
98 
99                 value = e.Current;
100                 while (e.MoveNext())
101                 {
102                     long x = e.Current;
103                     if (x < value)
104                     {
105                         value = x;
106                     }
107                 }
108             }
109 
110             return value;
111         }
112 
Min(this IEnumerable<long?> source)113         public static long? Min(this IEnumerable<long?> source)
114         {
115             if (source == null)
116             {
117                 throw Error.ArgumentNull(nameof(source));
118             }
119 
120             long? value = null;
121             using (IEnumerator<long?> e = source.GetEnumerator())
122             {
123                 do
124                 {
125                     if (!e.MoveNext())
126                     {
127                         return value;
128                     }
129 
130                     value = e.Current;
131                 }
132                 while (!value.HasValue);
133 
134                 long valueVal = value.GetValueOrDefault();
135                 while (e.MoveNext())
136                 {
137                     long? cur = e.Current;
138                     long x = cur.GetValueOrDefault();
139 
140                     // Do not replace & with &&. The branch prediction cost outweighs the extra operation
141                     // unless nulls either never happen or always happen.
142                     if (cur.HasValue & x < valueVal)
143                     {
144                         valueVal = x;
145                         value = cur;
146                     }
147                 }
148             }
149 
150             return value;
151         }
152 
Min(this IEnumerable<float> source)153         public static float Min(this IEnumerable<float> source)
154         {
155             if (source == null)
156             {
157                 throw Error.ArgumentNull(nameof(source));
158             }
159 
160             float value;
161             using (IEnumerator<float> e = source.GetEnumerator())
162             {
163                 if (!e.MoveNext())
164                 {
165                     throw Error.NoElements();
166                 }
167 
168                 value = e.Current;
169                 while (e.MoveNext())
170                 {
171                     float x = e.Current;
172                     if (x < value)
173                     {
174                         value = x;
175                     }
176 
177                     // Normally NaN < anything is false, as is anything < NaN
178                     // However, this leads to some irksome outcomes in Min and Max.
179                     // If we use those semantics then Min(NaN, 5.0) is NaN, but
180                     // Min(5.0, NaN) is 5.0!  To fix this, we impose a total
181                     // ordering where NaN is smaller than every value, including
182                     // negative infinity.
183                     // Not testing for NaN therefore isn't an option, but since we
184                     // can't find a smaller value, we can short-circuit.
185                     else if (float.IsNaN(x))
186                     {
187                         return x;
188                     }
189                 }
190             }
191 
192             return value;
193         }
194 
Min(this IEnumerable<float?> source)195         public static float? Min(this IEnumerable<float?> source)
196         {
197             if (source == null)
198             {
199                 throw Error.ArgumentNull(nameof(source));
200             }
201 
202             float? value = null;
203             using (IEnumerator<float?> e = source.GetEnumerator())
204             {
205                 do
206                 {
207                     if (!e.MoveNext())
208                     {
209                         return value;
210                     }
211 
212                     value = e.Current;
213                 }
214                 while (!value.HasValue);
215 
216                 float valueVal = value.GetValueOrDefault();
217                 while (e.MoveNext())
218                 {
219                     float? cur = e.Current;
220                     if (cur.HasValue)
221                     {
222                         float x = cur.GetValueOrDefault();
223                         if (x < valueVal)
224                         {
225                             valueVal = x;
226                             value = cur;
227                         }
228                         else if (float.IsNaN(x))
229                         {
230                             return cur;
231                         }
232                     }
233                 }
234             }
235 
236             return value;
237         }
238 
Min(this IEnumerable<double> source)239         public static double Min(this IEnumerable<double> source)
240         {
241             if (source == null)
242             {
243                 throw Error.ArgumentNull(nameof(source));
244             }
245 
246             double value;
247             using (IEnumerator<double> e = source.GetEnumerator())
248             {
249                 if (!e.MoveNext())
250                 {
251                     throw Error.NoElements();
252                 }
253 
254                 value = e.Current;
255                 while (e.MoveNext())
256                 {
257                     double x = e.Current;
258                     if (x < value)
259                     {
260                         value = x;
261                     }
262                     else if (double.IsNaN(x))
263                     {
264                         return x;
265                     }
266                 }
267             }
268 
269             return value;
270         }
271 
Min(this IEnumerable<double?> source)272         public static double? Min(this IEnumerable<double?> source)
273         {
274             if (source == null)
275             {
276                 throw Error.ArgumentNull(nameof(source));
277             }
278 
279             double? value = null;
280             using (IEnumerator<double?> e = source.GetEnumerator())
281             {
282                 do
283                 {
284                     if (!e.MoveNext())
285                     {
286                         return value;
287                     }
288 
289                     value = e.Current;
290                 }
291                 while (!value.HasValue);
292 
293                 double valueVal = value.GetValueOrDefault();
294                 while (e.MoveNext())
295                 {
296                     double? cur = e.Current;
297                     if (cur.HasValue)
298                     {
299                         double x = cur.GetValueOrDefault();
300                         if (x < valueVal)
301                         {
302                             valueVal = x;
303                             value = cur;
304                         }
305                         else if (double.IsNaN(x))
306                         {
307                             return cur;
308                         }
309                     }
310                 }
311             }
312 
313             return value;
314         }
315 
Min(this IEnumerable<decimal> source)316         public static decimal Min(this IEnumerable<decimal> source)
317         {
318             if (source == null)
319             {
320                 throw Error.ArgumentNull(nameof(source));
321             }
322 
323             decimal value;
324             using (IEnumerator<decimal> e = source.GetEnumerator())
325             {
326                 if (!e.MoveNext())
327                 {
328                     throw Error.NoElements();
329                 }
330 
331                 value = e.Current;
332                 while (e.MoveNext())
333                 {
334                     decimal x = e.Current;
335                     if (x < value)
336                     {
337                         value = x;
338                     }
339                 }
340             }
341 
342             return value;
343         }
344 
Min(this IEnumerable<decimal?> source)345         public static decimal? Min(this IEnumerable<decimal?> source)
346         {
347             if (source == null)
348             {
349                 throw Error.ArgumentNull(nameof(source));
350             }
351 
352             decimal? value = null;
353             using (IEnumerator<decimal?> e = source.GetEnumerator())
354             {
355                 do
356                 {
357                     if (!e.MoveNext())
358                     {
359                         return value;
360                     }
361 
362                     value = e.Current;
363                 }
364                 while (!value.HasValue);
365 
366                 decimal valueVal = value.GetValueOrDefault();
367                 while (e.MoveNext())
368                 {
369                     decimal? cur = e.Current;
370                     decimal x = cur.GetValueOrDefault();
371                     if (cur.HasValue && x < valueVal)
372                     {
373                         valueVal = x;
374                         value = cur;
375                     }
376                 }
377             }
378 
379             return value;
380         }
381 
Min(this IEnumerable<TSource> source)382         public static TSource Min<TSource>(this IEnumerable<TSource> source)
383         {
384             if (source == null)
385             {
386                 throw Error.ArgumentNull(nameof(source));
387             }
388 
389             Comparer<TSource> comparer = Comparer<TSource>.Default;
390             TSource value = default(TSource);
391             if (value == null)
392             {
393                 using (IEnumerator<TSource> e = source.GetEnumerator())
394                 {
395                     do
396                     {
397                         if (!e.MoveNext())
398                         {
399                             return value;
400                         }
401 
402                         value = e.Current;
403                     }
404                     while (value == null);
405 
406                     while (e.MoveNext())
407                     {
408                         TSource x = e.Current;
409                         if (x != null && comparer.Compare(x, value) < 0)
410                         {
411                             value = x;
412                         }
413                     }
414                 }
415             }
416             else
417             {
418                 using (IEnumerator<TSource> e = source.GetEnumerator())
419                 {
420                     if (!e.MoveNext())
421                     {
422                         throw Error.NoElements();
423                     }
424 
425                     value = e.Current;
426                     while (e.MoveNext())
427                     {
428                         TSource x = e.Current;
429                         if (comparer.Compare(x, value) < 0)
430                         {
431                             value = x;
432                         }
433                     }
434                 }
435             }
436 
437             return value;
438         }
439 
Min(this IEnumerable<TSource> source, Func<TSource, int> selector)440         public static int Min<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
441         {
442             if (source == null)
443             {
444                 throw Error.ArgumentNull(nameof(source));
445             }
446 
447             if (selector == null)
448             {
449                 throw Error.ArgumentNull(nameof(selector));
450             }
451 
452             int value;
453             using (IEnumerator<TSource> e = source.GetEnumerator())
454             {
455                 if (!e.MoveNext())
456                 {
457                     throw Error.NoElements();
458                 }
459 
460                 value = selector(e.Current);
461                 while (e.MoveNext())
462                 {
463                     int x = selector(e.Current);
464                     if (x < value)
465                     {
466                         value = x;
467                     }
468                 }
469             }
470 
471             return value;
472         }
473 
Min(this IEnumerable<TSource> source, Func<TSource, int?> selector)474         public static int? Min<TSource>(this IEnumerable<TSource> source, Func<TSource, int?> selector)
475         {
476             if (source == null)
477             {
478                 throw Error.ArgumentNull(nameof(source));
479             }
480 
481             if (selector == null)
482             {
483                 throw Error.ArgumentNull(nameof(selector));
484             }
485 
486             int? value = null;
487             using (IEnumerator<TSource> e = source.GetEnumerator())
488             {
489                 // Start off knowing that we've a non-null value (or exit here, knowing we don't)
490                 // so we don't have to keep testing for nullity.
491                 do
492                 {
493                     if (!e.MoveNext())
494                     {
495                         return value;
496                     }
497 
498                     value = selector(e.Current);
499                 }
500                 while (!value.HasValue);
501 
502                 // Keep hold of the wrapped value, and do comparisons on that, rather than
503                 // using the lifted operation each time.
504                 int valueVal = value.GetValueOrDefault();
505                 while (e.MoveNext())
506                 {
507                     int? cur = selector(e.Current);
508                     int x = cur.GetValueOrDefault();
509 
510                     // Do not replace & with &&. The branch prediction cost outweighs the extra operation
511                     // unless nulls either never happen or always happen.
512                     if (cur.HasValue & x < valueVal)
513                     {
514                         valueVal = x;
515                         value = cur;
516                     }
517                 }
518             }
519 
520             return value;
521         }
522 
Min(this IEnumerable<TSource> source, Func<TSource, long> selector)523         public static long Min<TSource>(this IEnumerable<TSource> source, Func<TSource, long> selector)
524         {
525             if (source == null)
526             {
527                 throw Error.ArgumentNull(nameof(source));
528             }
529 
530             if (selector == null)
531             {
532                 throw Error.ArgumentNull(nameof(selector));
533             }
534 
535             long value;
536             using (IEnumerator<TSource> e = source.GetEnumerator())
537             {
538                 if (!e.MoveNext())
539                 {
540                     throw Error.NoElements();
541                 }
542 
543                 value = selector(e.Current);
544                 while (e.MoveNext())
545                 {
546                     long x = selector(e.Current);
547                     if (x < value)
548                     {
549                         value = x;
550                     }
551                 }
552             }
553 
554             return value;
555         }
556 
Min(this IEnumerable<TSource> source, Func<TSource, long?> selector)557         public static long? Min<TSource>(this IEnumerable<TSource> source, Func<TSource, long?> selector)
558         {
559             if (source == null)
560             {
561                 throw Error.ArgumentNull(nameof(source));
562             }
563 
564             if (selector == null)
565             {
566                 throw Error.ArgumentNull(nameof(selector));
567             }
568 
569             long? value = null;
570             using (IEnumerator<TSource> e = source.GetEnumerator())
571             {
572                 do
573                 {
574                     if (!e.MoveNext())
575                     {
576                         return value;
577                     }
578 
579                     value = selector(e.Current);
580                 }
581                 while (!value.HasValue);
582 
583                 long valueVal = value.GetValueOrDefault();
584                 while (e.MoveNext())
585                 {
586                     long? cur = selector(e.Current);
587                     long x = cur.GetValueOrDefault();
588 
589                     // Do not replace & with &&. The branch prediction cost outweighs the extra operation
590                     // unless nulls either never happen or always happen.
591                     if (cur.HasValue & x < valueVal)
592                     {
593                         valueVal = x;
594                         value = cur;
595                     }
596                 }
597             }
598 
599             return value;
600         }
601 
Min(this IEnumerable<TSource> source, Func<TSource, float> selector)602         public static float Min<TSource>(this IEnumerable<TSource> source, Func<TSource, float> selector)
603         {
604             if (source == null)
605             {
606                 throw Error.ArgumentNull(nameof(source));
607             }
608 
609             if (selector == null)
610             {
611                 throw Error.ArgumentNull(nameof(selector));
612             }
613 
614             float value;
615             using (IEnumerator<TSource> e = source.GetEnumerator())
616             {
617                 if (!e.MoveNext())
618                 {
619                     throw Error.NoElements();
620                 }
621 
622                 value = selector(e.Current);
623                 while (e.MoveNext())
624                 {
625                     float x = selector(e.Current);
626                     if (x < value)
627                     {
628                         value = x;
629                     }
630 
631                     // Normally NaN < anything is false, as is anything < NaN
632                     // However, this leads to some irksome outcomes in Min and Max.
633                     // If we use those semantics then Min(NaN, 5.0) is NaN, but
634                     // Min(5.0, NaN) is 5.0!  To fix this, we impose a total
635                     // ordering where NaN is smaller than every value, including
636                     // negative infinity.
637                     // Not testing for NaN therefore isn't an option, but since we
638                     // can't find a smaller value, we can short-circuit.
639                     else if (float.IsNaN(x))
640                     {
641                         return x;
642                     }
643                 }
644             }
645 
646             return value;
647         }
648 
Min(this IEnumerable<TSource> source, Func<TSource, float?> selector)649         public static float? Min<TSource>(this IEnumerable<TSource> source, Func<TSource, float?> selector)
650         {
651             if (source == null)
652             {
653                 throw Error.ArgumentNull(nameof(source));
654             }
655 
656             if (selector == null)
657             {
658                 throw Error.ArgumentNull(nameof(selector));
659             }
660 
661             float? value = null;
662             using (IEnumerator<TSource> e = source.GetEnumerator())
663             {
664                 do
665                 {
666                     if (!e.MoveNext())
667                     {
668                         return value;
669                     }
670 
671                     value = selector(e.Current);
672                 }
673                 while (!value.HasValue);
674 
675                 float valueVal = value.GetValueOrDefault();
676                 while (e.MoveNext())
677                 {
678                     float? cur = selector(e.Current);
679                     if (cur.HasValue)
680                     {
681                         float x = cur.GetValueOrDefault();
682                         if (x < valueVal)
683                         {
684                             valueVal = x;
685                             value = cur;
686                         }
687                         else if (float.IsNaN(x))
688                         {
689                             return cur;
690                         }
691                     }
692                 }
693             }
694 
695             return value;
696         }
697 
Min(this IEnumerable<TSource> source, Func<TSource, double> selector)698         public static double Min<TSource>(this IEnumerable<TSource> source, Func<TSource, double> selector)
699         {
700             if (source == null)
701             {
702                 throw Error.ArgumentNull(nameof(source));
703             }
704 
705             if (selector == null)
706             {
707                 throw Error.ArgumentNull(nameof(selector));
708             }
709 
710             double value;
711             using (IEnumerator<TSource> e = source.GetEnumerator())
712             {
713                 if (!e.MoveNext())
714                 {
715                     throw Error.NoElements();
716                 }
717 
718                 value = selector(e.Current);
719                 while (e.MoveNext())
720                 {
721                     double x = selector(e.Current);
722                     if (x < value)
723                     {
724                         value = x;
725                     }
726                     else if (double.IsNaN(x))
727                     {
728                         return x;
729                     }
730                 }
731             }
732 
733             return value;
734         }
735 
Min(this IEnumerable<TSource> source, Func<TSource, double?> selector)736         public static double? Min<TSource>(this IEnumerable<TSource> source, Func<TSource, double?> selector)
737         {
738             if (source == null)
739             {
740                 throw Error.ArgumentNull(nameof(source));
741             }
742 
743             if (selector == null)
744             {
745                 throw Error.ArgumentNull(nameof(selector));
746             }
747 
748             double? value = null;
749             using (IEnumerator<TSource> e = source.GetEnumerator())
750             {
751                 do
752                 {
753                     if (!e.MoveNext())
754                     {
755                         return value;
756                     }
757 
758                     value = selector(e.Current);
759                 }
760                 while (!value.HasValue);
761 
762                 double valueVal = value.GetValueOrDefault();
763                 while (e.MoveNext())
764                 {
765                     double? cur = selector(e.Current);
766                     if (cur.HasValue)
767                     {
768                         double x = cur.GetValueOrDefault();
769                         if (x < valueVal)
770                         {
771                             valueVal = x;
772                             value = cur;
773                         }
774                         else if (double.IsNaN(x))
775                         {
776                             return cur;
777                         }
778                     }
779                 }
780             }
781 
782             return value;
783         }
784 
Min(this IEnumerable<TSource> source, Func<TSource, decimal> selector)785         public static decimal Min<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal> selector)
786         {
787             if (source == null)
788             {
789                 throw Error.ArgumentNull(nameof(source));
790             }
791 
792             if (selector == null)
793             {
794                 throw Error.ArgumentNull(nameof(selector));
795             }
796 
797             decimal value;
798             using (IEnumerator<TSource> e = source.GetEnumerator())
799             {
800                 if (!e.MoveNext())
801                 {
802                     throw Error.NoElements();
803                 }
804 
805                 value = selector(e.Current);
806                 while (e.MoveNext())
807                 {
808                     decimal x = selector(e.Current);
809                     if (x < value)
810                     {
811                         value = x;
812                     }
813                 }
814             }
815 
816             return value;
817         }
818 
Min(this IEnumerable<TSource> source, Func<TSource, decimal?> selector)819         public static decimal? Min<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
820         {
821             if (source == null)
822             {
823                 throw Error.ArgumentNull(nameof(source));
824             }
825 
826             if (selector == null)
827             {
828                 throw Error.ArgumentNull(nameof(selector));
829             }
830 
831             decimal? value = null;
832             using (IEnumerator<TSource> e = source.GetEnumerator())
833             {
834                 do
835                 {
836                     if (!e.MoveNext())
837                     {
838                         return value;
839                     }
840 
841                     value = selector(e.Current);
842                 }
843                 while (!value.HasValue);
844 
845                 decimal valueVal = value.GetValueOrDefault();
846                 while (e.MoveNext())
847                 {
848                     decimal? cur = selector(e.Current);
849                     decimal x = cur.GetValueOrDefault();
850                     if (cur.HasValue && x < valueVal)
851                     {
852                         valueVal = x;
853                         value = cur;
854                     }
855                 }
856             }
857 
858             return value;
859         }
860 
Min(this IEnumerable<TSource> source, Func<TSource, TResult> selector)861         public static TResult Min<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
862         {
863             if (source == null)
864             {
865                 throw Error.ArgumentNull(nameof(source));
866             }
867 
868             if (selector == null)
869             {
870                 throw Error.ArgumentNull(nameof(selector));
871             }
872 
873             Comparer<TResult> comparer = Comparer<TResult>.Default;
874             TResult value = default(TResult);
875             if (value == null)
876             {
877                 using (IEnumerator<TSource> e = source.GetEnumerator())
878                 {
879                     do
880                     {
881                         if (!e.MoveNext())
882                         {
883                             return value;
884                         }
885 
886                         value = selector(e.Current);
887                     }
888                     while (value == null);
889 
890                     while (e.MoveNext())
891                     {
892                         TResult x = selector(e.Current);
893                         if (x != null && comparer.Compare(x, value) < 0)
894                         {
895                             value = x;
896                         }
897                     }
898                 }
899             }
900             else
901             {
902                 using (IEnumerator<TSource> e = source.GetEnumerator())
903                 {
904                     if (!e.MoveNext())
905                     {
906                         throw Error.NoElements();
907                     }
908 
909                     value = selector(e.Current);
910                     while (e.MoveNext())
911                     {
912                         TResult x = selector(e.Current);
913                         if (comparer.Compare(x, value) < 0)
914                         {
915                             value = x;
916                         }
917                     }
918                 }
919             }
920 
921             return value;
922         }
923     }
924 }
925