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