2008-01-21 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / System.Core / System.Linq / Enumerable.cs
1 //
2 // Enumerable.cs
3 //
4 // Authors:
5 //  Marek Safar (marek.safar@gmail.com)
6 //  Antonello Provenzano  <antonello@deveel.com>
7 //  Alejandro Serrano "Serras" (trupill@yahoo.es)
8 //  Jb Evain (jbevain@novell.com)
9 //
10 // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 // precious: http://www.hookedonlinq.com
33
34 using System;
35 using System.Collections;
36 using System.Collections.Generic;
37 using System.Collections.ObjectModel;
38
39 namespace System.Linq
40 {
41         public static class Enumerable
42         {
43                 #region Aggregate
44
45                 public static TSource Aggregate<TSource> (this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
46                 {
47                         Check.SourceAndFunc (source, func);
48
49                         // custom foreach so that we can efficiently throw an exception
50                         // if zero elements and treat the first element differently
51                         using (var enumerator = source.GetEnumerator ()) {
52                                 if (!enumerator.MoveNext ())
53                                         throw new InvalidOperationException ("No elements in source list");
54
55                                 TSource folded = enumerator.Current;
56                                 while (enumerator.MoveNext ())
57                                         folded = func (folded, enumerator.Current);
58                                 return folded;
59                         }
60                 }
61
62                 public static TAccumulate Aggregate<TSource, TAccumulate> (this IEnumerable<TSource> source,
63                         TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)
64                 {
65                         Check.SourceAndFunc (source, func);
66
67                         TAccumulate folded = seed;
68                         foreach (TSource element in source)
69                                 folded = func (folded, element);
70
71                         return folded;
72                 }
73
74                 public static TResult Aggregate<TSource, TAccumulate, TResult> (this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func, Func<TAccumulate, TResult> resultSelector)
75                 {
76                         Check.SourceAndFunc (source, func);
77                         if (resultSelector == null)
78                                 throw new ArgumentNullException ("resultSelector");
79
80                         TAccumulate result = seed;
81                         foreach (TSource e in source)
82                                 result = func (result, e);
83
84                         return resultSelector (result);
85                 }
86
87                 #endregion
88
89                 #region All
90
91                 public static bool All<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
92                 {
93                         Check.SourceAndPredicate (source, predicate);
94
95                         foreach (TSource element in source)
96                                 if (!predicate (element))
97                                         return false;
98
99                         return true;
100                 }
101
102                 #endregion
103
104                 #region Any
105
106                 public static bool Any<TSource> (this IEnumerable<TSource> source)
107                 {
108                         Check.Source (source);
109
110                         using (var enumerator = source.GetEnumerator ())
111                                 return enumerator.MoveNext ();
112                 }
113
114                 public static bool Any<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
115                 {
116                         Check.SourceAndPredicate (source, predicate);
117
118                         foreach (TSource element in source)
119                                 if (predicate (element))
120                                         return true;
121
122                         return false;
123                 }
124
125                 #endregion
126
127                 #region AsEnumerable
128
129                 public static IEnumerable<TSource> AsEnumerable<TSource> (this IEnumerable<TSource> source)
130                 {
131                         return source;
132                 }
133
134                 #endregion
135
136                 #region Average
137
138                 public static double Average (this IEnumerable<int> source)
139                 {
140                         return Average (source, (a, b) => a + b, (a, b) => a / b);
141                 }
142
143                 public static double Average (this IEnumerable<long> source)
144                 {
145                         return Average (source, (a, b) => a + b, (a, b) => a / b);
146                 }
147
148                 public static double Average (this IEnumerable<double> source)
149                 {
150                         return Average (source, (a, b) => a + b, (a, b) => a / b);
151                 }
152
153                 public static float Average (this IEnumerable<float> source)
154                 {
155                         return Average (source, (a, b) => a + b, (a, b) => a / b);
156                 }
157
158                 public static decimal Average (this IEnumerable<decimal> source)
159                 {
160                         return Average (source, (a, b) => a + b, (a, b) => a / b);
161                 }
162
163                 static TR Average<TA, TR> (this IEnumerable<TA> source, Func<TA, TA, TA> func, Func<TA, int, TR> result)
164                 {
165                         Check.Source (source);
166
167                         TA total = default (TA);
168                         int counter = 0;
169                         foreach (var element in source) {
170                                 total = func (total, element);
171                                 ++counter;
172                         }
173
174                         if (counter == 0)
175                                 throw new InvalidOperationException ();
176
177                         return result (total, counter);
178                 }
179
180                 public static double? Average (this IEnumerable<int?> source)
181                 {
182                         Check.Source (source);
183
184                         bool onlyNull = true;
185                         long sum = 0;
186                         long counter = 0;
187                         foreach (int? element in source) {
188                                 if (element.HasValue) {
189                                         onlyNull = false;
190                                         sum += element.Value;
191                                         counter++;
192                                 }
193                         }
194                         return (onlyNull ? null : (double?) sum / (double?) counter);
195                 }
196
197                 public static double? Average (this IEnumerable<long?> source)
198                 {
199                         Check.Source (source);
200
201                         bool onlyNull = true;
202                         long sum = 0;
203                         long counter = 0;
204                         foreach (long? element in source) {
205                                 if (element.HasValue) {
206                                         onlyNull = false;
207                                         sum += element.Value;
208                                         counter++;
209                                 }
210                         }
211                         return (onlyNull ? null : (double?) sum / (double?) counter);
212                 }
213
214                 public static double? Average (this IEnumerable<double?> source)
215                 {
216                         Check.Source (source);
217
218                         bool onlyNull = true;
219                         double sum = 0;
220                         double counter = 0;
221                         foreach (double? element in source) {
222                                 if (element.HasValue) {
223                                         onlyNull = false;
224                                         sum += element.Value;
225                                         counter++;
226                                 }
227                         }
228                         return (onlyNull ? null : (double?) (sum / counter));
229                 }
230
231                 public static decimal? Average (this IEnumerable<decimal?> source)
232                 {
233                         Check.Source (source);
234
235                         bool onlyNull = true;
236                         decimal sum = 0;
237                         decimal counter = 0;
238                         foreach (decimal? element in source) {
239                                 if (element.HasValue) {
240                                         onlyNull = false;
241                                         sum += element.Value;
242                                         counter++;
243                                 }
244                         }
245                         return (onlyNull ? null : (decimal?) (sum / counter));
246                 }
247
248                 public static float? Average (this IEnumerable<float?> source)
249                 {
250                         Check.Source (source);
251
252                         float sum = 0;
253                         float counter = 0;
254                         foreach (float? element in source) {
255                                 if (element.HasValue) {
256                                         sum += element.Value;
257                                         ++counter;
258                                 }
259                         }
260
261                         if (counter == 0)
262                                 return null;
263
264                         return sum / counter;
265                 }
266
267                 public static double Average<TSource> (this IEnumerable<TSource> source, Func<TSource, int> selector)
268                 {
269                         Check.SourceAndSelector (source, selector);
270
271                         long sum = 0;
272                         long counter = 0;
273                         foreach (TSource item in source) {
274                                 sum += selector (item);
275                                 counter++;
276                         }
277
278                         if (counter == 0)
279                                 throw new InvalidOperationException ();
280                         else
281                                 return (double) sum / (double) counter;
282                 }
283
284                 public static double? Average<TSource> (this IEnumerable<TSource> source, Func<TSource, int?> selector)
285                 {
286                         Check.SourceAndSelector (source, selector);
287
288                         bool onlyNull = true;
289                         long sum = 0;
290                         long counter = 0;
291                         foreach (TSource item in source) {
292                                 int? element = selector (item);
293                                 if (element.HasValue) {
294                                         onlyNull = false;
295                                         sum += element.Value;
296                                         counter++;
297                                 }
298                         }
299                         return (onlyNull ? null : (double?) sum / (double?) counter);
300                 }
301
302                 public static double Average<TSource> (this IEnumerable<TSource> source, Func<TSource, long> selector)
303                 {
304                         Check.SourceAndSelector (source, selector);
305
306                         long sum = 0;
307                         long counter = 0;
308                         foreach (TSource item in source) {
309                                 sum += selector (item);
310                                 counter++;
311                         }
312
313                         if (counter == 0)
314                                 throw new InvalidOperationException ();
315                         else
316                                 return (double) sum / (double) counter;
317                 }
318
319                 public static double? Average<TSource> (this IEnumerable<TSource> source, Func<TSource, long?> selector)
320                 {
321                         Check.SourceAndSelector (source, selector);
322
323                         bool onlyNull = true;
324                         long sum = 0;
325                         long counter = 0;
326                         foreach (TSource item in source) {
327                                 long? element = selector (item);
328                                 if (element.HasValue) {
329                                         onlyNull = false;
330                                         sum += element.Value;
331                                         counter++;
332                                 }
333                         }
334                         return (onlyNull ? null : (double?) sum / (double?) counter);
335                 }
336
337                 public static double Average<TSource> (this IEnumerable<TSource> source, Func<TSource, double> selector)
338                 {
339                         Check.SourceAndSelector (source, selector);
340
341                         double sum = 0;
342                         double counter = 0;
343                         foreach (TSource item in source) {
344                                 sum += selector (item);
345                                 counter++;
346                         }
347
348                         if (counter == 0)
349                                 throw new InvalidOperationException ();
350                         else
351                                 return sum / counter;
352                 }
353
354                 public static double? Average<TSource> (this IEnumerable<TSource> source, Func<TSource, double?> selector)
355                 {
356                         Check.SourceAndSelector (source, selector);
357
358                         bool onlyNull = true;
359                         double sum = 0;
360                         double counter = 0;
361                         foreach (TSource item in source) {
362                                 double? element = selector (item);
363                                 if (element.HasValue) {
364                                         onlyNull = false;
365                                         sum += element.Value;
366                                         counter++;
367                                 }
368                         }
369                         return (onlyNull ? null : (double?) (sum / counter));
370                 }
371
372                 public static float Average<TSource> (this IEnumerable<TSource> source, Func<TSource, float> selector)
373                 {
374                         Check.SourceAndSelector (source, selector);
375
376                         float sum = 0;
377                         float counter = 0;
378                         foreach (TSource item in source) {
379                                 sum += selector (item);
380                                 ++counter;
381                         }
382
383                         if (counter == 0)
384                                 throw new InvalidOperationException ();
385
386                         return sum / counter;
387                 }
388
389                 public static float? Average<TSource> (this IEnumerable<TSource> source, Func<TSource, float?> selector)
390                 {
391                         Check.SourceAndSelector (source, selector);
392
393                         float sum = 0;
394                         float counter = 0;
395                         foreach (TSource item in source) {
396                                 float? value = selector (item);
397                                 if (value.HasValue) {
398                                         sum  += value.Value;
399                                         ++counter;
400                                 }
401                         }
402
403                         if (counter == 0)
404                                 throw new InvalidOperationException ();
405
406                         return sum / counter;
407                 }
408
409                 public static decimal Average<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal> selector)
410                 {
411                         Check.SourceAndSelector (source, selector);
412
413                         decimal sum = 0;
414                         decimal counter = 0;
415                         foreach (TSource item in source) {
416                                 sum += selector (item);
417                                 counter++;
418                         }
419
420                         if (counter == 0)
421                                 throw new InvalidOperationException ();
422                         else
423                                 return sum / counter;
424                 }
425
426                 public static decimal? Average<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
427                 {
428                         Check.SourceAndSelector (source, selector);
429
430                         bool onlyNull = true;
431                         decimal sum = 0;
432                         decimal counter = 0;
433                         foreach (TSource item in source) {
434                                 decimal? element = selector (item);
435                                 if (element.HasValue) {
436                                         onlyNull = false;
437                                         sum += element.Value;
438                                         counter++;
439                                 }
440                         }
441                         return (onlyNull ? null : (decimal?) (sum / counter));
442                 }
443                 #endregion
444
445                 #region Cast
446
447                 public static IEnumerable<TResult> Cast<TResult> (this IEnumerable source)
448                 {
449                         Check.Source (source);
450
451                         return CreateCastIterator<TResult> (source);
452                 }
453
454                 static IEnumerable<TResult> CreateCastIterator<TResult> (IEnumerable source)
455                 {
456                         foreach (object element in source)
457                                 yield return (TResult) element;
458                 }
459
460                 #endregion
461
462                 #region Concat
463
464                 public static IEnumerable<TSource> Concat<TSource> (this IEnumerable<TSource> first, IEnumerable<TSource> second)
465                 {
466                         Check.FirstAndSecond (first, second);
467
468                         foreach (TSource element in first)
469                                 yield return element;
470                         foreach (TSource element in second)
471                                 yield return element;
472                 }
473
474                 #endregion
475
476                 #region Contains
477
478                 public static bool Contains<TSource> (this IEnumerable<TSource> source, TSource value)
479                 {
480                         var collection = source as ICollection<TSource>;
481                         if (collection != null)
482                                 return collection.Contains (value);
483
484                         return Contains<TSource> (source, value, null);
485                 }
486
487                 public static bool Contains<TSource> (this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
488                 {
489                         Check.Source (source);
490
491                         if (comparer == null)
492                                 comparer = EqualityComparer<TSource>.Default;
493
494                         foreach (TSource e in source) {
495                                 if (comparer.Equals (e, value))
496                                         return true;
497                         }
498
499                         return false;
500                 }
501                 #endregion
502
503                 #region Count
504
505                 public static int Count<TSource> (this IEnumerable<TSource> source)
506                 {
507                         Check.Source (source);
508
509                         var collection = source as ICollection<TSource>;
510                         if (collection != null)
511                                 return collection.Count;
512
513                         int counter = 0;
514                         using (var enumerator = source.GetEnumerator ())
515                                 while (enumerator.MoveNext ())
516                                         counter++;
517
518                         return counter;
519                 }
520
521                 public static int Count<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> selector)
522                 {
523                         Check.SourceAndSelector (source, selector);
524
525                         int counter = 0;
526                         foreach (var element in source)
527                                 if (selector (element))
528                                         counter++;
529
530                         return counter;
531                 }
532
533                 #endregion
534
535                 #region DefaultIfEmpty
536
537                 public static IEnumerable<TSource> DefaultIfEmpty<TSource> (this IEnumerable<TSource> source)
538                 {
539                         return DefaultIfEmpty (source, default (TSource));
540                 }
541
542                 public static IEnumerable<TSource> DefaultIfEmpty<TSource> (this IEnumerable<TSource> source, TSource defaultValue)
543                 {
544                         Check.Source (source);
545
546                         return CreateDefaultIfEmptyIterator (source, defaultValue);
547                 }
548
549                 static IEnumerable<TSource> CreateDefaultIfEmptyIterator<TSource> (IEnumerable<TSource> source, TSource defaultValue)
550                 {
551                         bool empty = true;
552                         foreach (TSource item in source) {
553                                 empty = false;
554                                 yield return item;
555                         }
556
557                         if (empty)
558                                 yield return defaultValue;
559                 }
560
561                 #endregion
562
563                 #region Distinct
564
565                 public static IEnumerable<TSource> Distinct<TSource> (this IEnumerable<TSource> source)
566                 {
567                         return Distinct<TSource> (source, null);
568                 }
569
570                 public static IEnumerable<TSource> Distinct<TSource> (this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
571                 {
572                         Check.Source (source);
573
574                         if (comparer == null)
575                                 comparer = EqualityComparer<TSource>.Default;
576
577                         return CreateDistinctIterator (source, comparer);
578                 }
579
580                 static IEnumerable<TSource> CreateDistinctIterator<TSource> (IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
581                 {
582                         var items = new HashSet<TSource> ();
583                         foreach (var element in source) {
584                                 if (! items.Contains (element, comparer)) {
585                                         items.Add (element);
586                                         yield return element;
587                                 }
588                         }
589                 }
590
591                 #endregion
592
593                 #region ElementAt
594
595                 public static TSource ElementAt<TSource> (this IEnumerable<TSource> source, int index)
596                 {
597                         Check.Source (source);
598                         if (index < 0)
599                                 throw new ArgumentOutOfRangeException ();
600
601                         var list = source as IList<TSource>;
602                         if (list != null)
603                                 return list [index];
604
605                         int counter = 0;
606                         foreach (var element in source) {
607                                 if (counter == index)
608                                         return element;
609                                 counter++;
610                         }
611
612                         throw new ArgumentOutOfRangeException ();
613                 }
614
615                 #endregion
616
617                 #region ElementAtOrDefault
618
619                 public static TSource ElementAtOrDefault<TSource> (this IEnumerable<TSource> source, int index)
620                 {
621                         Check.Source (source);
622                         if (index < 0)
623                                 return default (TSource);
624
625                         var list = source as IList<TSource>;
626                         if (list != null)
627                                 return index < list.Count ? list [index] : default (TSource);
628
629                         int counter = 0;
630                         foreach (TSource element in source) {
631                                 if (counter == index)
632                                         return element;
633                                 counter++;
634                         }
635
636                         return default (TSource);
637                 }
638
639                 #endregion
640
641                 #region Empty
642
643                 public static IEnumerable<TResult> Empty<TResult> ()
644                 {
645                         return new TResult [0];
646                 }
647
648                 #endregion
649
650                 #region Except
651
652                 public static IEnumerable<TSource> Except<TSource> (this IEnumerable<TSource> first, IEnumerable<TSource> second)
653                 {
654                         return Except (first, second, null);
655                 }
656
657                 public static IEnumerable<TSource> Except<TSource> (this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
658                 {
659                         Check.FirstAndSecond (first, second);
660
661                         if (comparer == null)
662                                 comparer = EqualityComparer<TSource>.Default;
663
664                         return CreateExceptIterator (first, second, comparer);
665                 }
666
667                 static IEnumerable<TSource> CreateExceptIterator<TSource> (IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
668                 {
669                         var items = new HashSet<TSource> (Distinct (second));
670                         foreach (TSource element in first) {
671                                 if (! items.Contains (element, comparer))
672                                         yield return element;
673                         }
674                 }
675
676                 #endregion
677
678                 #region First
679
680                 public static TSource First<TSource> (this IEnumerable<TSource> source)
681                 {
682                         Check.Source (source);
683
684                         foreach (TSource element in source)
685                                 return element;
686
687                         throw new InvalidOperationException ();
688                 }
689
690
691                 public static TSource First<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
692                 {
693                         Check.SourceAndPredicate (source, predicate);
694
695                         foreach (TSource element in source) {
696                                 if (predicate (element))
697                                         return element;
698                         }
699
700                         throw new InvalidOperationException ();
701                 }
702
703                 #endregion
704
705                 #region FirstOrDefault
706
707                 public static TSource FirstOrDefault<TSource> (this IEnumerable<TSource> source)
708                 {
709                         Check.Source (source);
710
711                         foreach (TSource element in source)
712                                 return element;
713
714                         return default (TSource);
715                 }
716
717
718                 public static TSource FirstOrDefault<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
719                 {
720                         Check.SourceAndPredicate (source, predicate);
721
722                         foreach (TSource element in source) {
723                                 if (predicate (element))
724                                         return element;
725                         }
726
727                         return default (TSource);
728                 }
729
730                 #endregion
731
732                 #region GroupBy
733
734                 private static List<T> ContainsGroup<K, T> (
735                                 Dictionary<K, List<T>> items, K key, IEqualityComparer<K> comparer)
736                 {
737                         IEqualityComparer<K> comparerInUse = (comparer ?? EqualityComparer<K>.Default);
738                         foreach (KeyValuePair<K, List<T>> value in items) {
739                                 if (comparerInUse.Equals (value.Key, key))
740                                         return value.Value;
741                         }
742                         return null;
743                 }
744
745
746                 public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey> (this IEnumerable<TSource> source,
747                         Func<TSource, TKey> keySelector)
748                 {
749                         return GroupBy<TSource, TKey> (source, keySelector, null);
750                 }
751
752                 public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey> (this IEnumerable<TSource> source,
753                         Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
754                 {
755                         Check.SourceAndKeySelector (source, keySelector);
756
757                         Dictionary<TKey, List<TSource>> groups = new Dictionary<TKey, List<TSource>> ();
758                         List<TSource> nullList = new List<TSource> ();
759                         int counter = 0;
760                         int nullCounter = -1;
761
762                         foreach (TSource element in source) {
763                                 TKey key = keySelector (element);
764                                 if (key == null) {
765                                         nullList.Add (element);
766                                         if (nullCounter == -1) {
767                                                 nullCounter = counter;
768                                                 counter++;
769                                         }
770                                 } else {
771                                         List<TSource> group = ContainsGroup<TKey, TSource> (groups, key, comparer);
772                                         if (group == null) {
773                                                 group = new List<TSource> ();
774                                                 groups.Add (key, group);
775                                                 counter++;
776                                         }
777                                         group.Add (element);
778                                 }
779                         }
780
781                         counter = 0;
782                         foreach (KeyValuePair<TKey, List<TSource>> group in groups) {
783                                 if (counter == nullCounter) {
784                                         Grouping<TKey, TSource> nullGroup = new Grouping<TKey, TSource> (default (TKey), nullList);
785                                         yield return nullGroup;
786                                         counter++;
787                                 }
788                                 Grouping<TKey, TSource> grouping = new Grouping<TKey, TSource> (group.Key, group.Value);
789                                 yield return grouping;
790                                 counter++;
791                         }
792                 }
793
794
795                 public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement> (this IEnumerable<TSource> source,
796                         Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
797                 {
798                         return GroupBy<TSource, TKey, TElement> (source, keySelector, elementSelector, null);
799                 }
800
801                 public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement> (this IEnumerable<TSource> source,
802                         Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
803                 {
804                         Check.SourceAndKeyElementSelectors (source, keySelector, elementSelector);
805
806                         Dictionary<TKey, List<TElement>> groups = new Dictionary<TKey, List<TElement>> ();
807                         List<TElement> nullList = new List<TElement> ();
808                         int counter = 0;
809                         int nullCounter = -1;
810
811                         foreach (TSource item in source) {
812                                 TKey key = keySelector (item);
813                                 TElement element = elementSelector (item);
814                                 if (key == null) {
815                                         nullList.Add (element);
816                                         if (nullCounter == -1) {
817                                                 nullCounter = counter;
818                                                 counter++;
819                                         }
820                                 } else {
821                                         List<TElement> group = ContainsGroup<TKey, TElement> (groups, key, comparer);
822                                         if (group == null) {
823                                                 group = new List<TElement> ();
824                                                 groups.Add (key, group);
825                                                 counter++;
826                                         }
827                                         group.Add (element);
828                                 }
829                         }
830
831                         counter = 0;
832                         foreach (KeyValuePair<TKey, List<TElement>> group in groups) {
833                                 if (counter == nullCounter) {
834                                         Grouping<TKey, TElement> nullGroup = new Grouping<TKey, TElement> (default (TKey), nullList);
835                                         yield return nullGroup;
836                                         counter++;
837                                 }
838                                 Grouping<TKey, TElement> grouping = new Grouping<TKey, TElement> (group.Key, group.Value);
839                                 yield return grouping;
840                                 counter++;
841                         }
842                 }
843
844                 public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult> (this IEnumerable<TSource> source,
845                         Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector,
846                         Func<TKey, IEnumerable<TElement>, TResult> resultSelector)
847                 {
848                         return GroupBy (source, keySelector, elementSelector, resultSelector, null);
849                 }
850
851                 [MonoTODO]
852                 public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult> (this IEnumerable<TSource> source,
853                         Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector,
854                         Func<TKey, IEnumerable<TElement>, TResult> resultSelector,
855                         IEqualityComparer<TKey> comparer)
856                 {
857                         throw new NotImplementedException ();
858                 }
859
860                 public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult> (this IEnumerable<TSource> source,
861                         Func<TSource, TKey> keySelector,
862                         Func<TKey, IEnumerable<TSource>, TResult> resultSelector)
863                 {
864                         return GroupBy (source, keySelector, resultSelector, null);
865                 }
866
867                 [MonoTODO]
868                 public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult> (this IEnumerable<TSource> source,
869                         Func<TSource, TKey> keySelector,
870                         Func<TKey, IEnumerable<TSource>, TResult> resultSelector,
871                         IEqualityComparer<TKey> comparer)
872                 {
873                         throw new NotImplementedException ();
874                 }
875
876                 #endregion
877
878                 # region GroupJoin
879
880                 public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult> (this IEnumerable<TOuter> outer,
881                         IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector,
882                         Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector)
883                 {
884                         return GroupJoin (outer, inner, outerKeySelector, innerKeySelector, resultSelector, null);
885                 }
886
887                 public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult> (this IEnumerable<TOuter> outer,
888                         IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector,
889                         Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector,
890                         IEqualityComparer<TKey> comparer)
891                 {
892                         Check.JoinSelectors (outer, inner, outerKeySelector, innerKeySelector, resultSelector);
893
894                         if (comparer == null)
895                                 comparer = EqualityComparer<TKey>.Default;
896
897                         ILookup<TKey, TInner> innerKeys = ToLookup<TInner, TKey> (inner, innerKeySelector, comparer);
898                         /*Dictionary<K, List<U>> innerKeys = new Dictionary<K, List<U>> ();
899                         foreach (U element in inner)
900                         {
901                                         K innerKey = innerKeySelector (element);
902                                         if (!innerKeys.ContainsKey (innerKey))
903                                                         innerKeys.Add (innerKey, new List<U> ());
904                                         innerKeys[innerKey].Add (element);
905                         }*/
906
907                         foreach (TOuter element in outer) {
908                                 TKey outerKey = outerKeySelector (element);
909                                 if (innerKeys.Contains (outerKey))
910                                         yield return resultSelector (element, innerKeys [outerKey]);
911                                 else
912                                         yield return resultSelector (element, Empty<TInner> ());
913                         }
914                 }
915
916                 #endregion
917
918                 #region Intersect
919
920                 public static IEnumerable<TSource> Intersect<TSource> (this IEnumerable<TSource> first, IEnumerable<TSource> second)
921                 {
922                         return Intersect (first, second, null);
923                 }
924
925                 public static IEnumerable<TSource> Intersect<TSource> (this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
926                 {
927                         Check.FirstAndSecond (first, second);
928
929                         if (comparer == null)
930                                 comparer = EqualityComparer<TSource>.Default;
931
932                         return CreateIntersectIterator (first, second, comparer);
933                 }
934
935                 static IEnumerable<TSource> CreateIntersectIterator<TSource> (IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
936                 {
937                         List<TSource> items = new List<TSource> (Distinct (first));
938                         foreach (TSource element in second) {
939                                 if (items.Contains (element, comparer))
940                                         yield return element;
941                         }
942                 }
943
944                 #endregion
945
946                 # region Join
947
948                 public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult> (this IEnumerable<TOuter> outer,
949                         IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector,
950                         Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer)
951                 {
952                         Check.JoinSelectors (outer, inner, outerKeySelector, innerKeySelector, resultSelector);
953
954                         if (comparer == null)
955                                 comparer = EqualityComparer<TKey>.Default;
956
957                         ILookup<TKey, TInner> innerKeys = ToLookup<TInner, TKey> (inner, innerKeySelector, comparer);
958                         /*Dictionary<K, List<U>> innerKeys = new Dictionary<K, List<U>> ();
959                         foreach (U element in inner)
960                         {
961                                         K innerKey = innerKeySelector (element);
962                                         if (!innerKeys.ContainsKey (innerKey))
963                                                         innerKeys.Add (innerKey, new List<U> ());
964                                         innerKeys[innerKey].Add (element);
965                         }*/
966
967                         foreach (TOuter element in outer) {
968                                 TKey outerKey = outerKeySelector (element);
969                                 if (innerKeys.Contains (outerKey)) {
970                                         foreach (TInner innerElement in innerKeys [outerKey])
971                                                 yield return resultSelector (element, innerElement);
972                                 }
973                         }
974                 }
975
976                 public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult> (this IEnumerable<TOuter> outer,
977                         IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector,
978                         Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector)
979                 {
980                         return Join<TOuter, TInner, TKey, TResult> (outer, inner, outerKeySelector, innerKeySelector, resultSelector, null);
981                 }
982
983                 # endregion
984
985                 #region Last
986
987                 public static TSource Last<TSource> (this IEnumerable<TSource> source)
988                 {
989                         Check.Source (source);
990
991                         bool noElements = true;
992                         TSource lastElement = default (TSource);
993                         foreach (TSource element in source) {
994                                 if (noElements) noElements = false;
995                                 lastElement = element;
996                         }
997
998                         if (!noElements)
999                                 return lastElement;
1000                         else
1001                                 throw new InvalidOperationException ();
1002                 }
1003
1004                 public static TSource Last<TSource> (this IEnumerable<TSource> source,
1005                                 Func<TSource, bool> predicate)
1006                 {
1007                         Check.SourceAndPredicate (source, predicate);
1008
1009                         bool noElements = true;
1010                         TSource lastElement = default (TSource);
1011                         foreach (TSource element in source) {
1012                                 if (predicate (element)) {
1013                                         if (noElements) noElements = false;
1014                                         lastElement = element;
1015                                 }
1016                         }
1017
1018                         if (!noElements)
1019                                 return lastElement;
1020                         else
1021                                 throw new InvalidOperationException ();
1022                 }
1023
1024                 #endregion
1025
1026                 #region LastOrDefault
1027
1028                 public static TSource LastOrDefault<TSource> (this IEnumerable<TSource> source)
1029                 {
1030                         Check.Source (source);
1031
1032                         var list = source as IList<TSource>;
1033                         if (list != null)
1034                                 return list.Count > 0 ? list [list.Count - 1] : default (TSource);
1035
1036                         TSource lastElement = default (TSource);
1037                         foreach (TSource element in source)
1038                                 lastElement = element;
1039
1040                         return lastElement;
1041                 }
1042
1043                 public static TSource LastOrDefault<TSource> (this IEnumerable<TSource> source,
1044                         Func<TSource, bool> predicate)
1045                 {
1046                         Check.SourceAndPredicate (source, predicate);
1047
1048                         TSource lastElement = default (TSource);
1049                         foreach (TSource element in source) {
1050                                 if (predicate (element))
1051                                         lastElement = element;
1052                         }
1053
1054                         return lastElement;
1055                 }
1056
1057                 #endregion
1058
1059                 #region LongCount
1060                 public static long LongCount<TSource> (this IEnumerable<TSource> source)
1061                 {
1062                         Check.Source (source);
1063
1064                         long counter = 0;
1065                         using (var enumerator = source.GetEnumerator ())
1066                                 while (enumerator.MoveNext ())
1067                                         counter++;
1068
1069                         return counter;
1070                 }
1071
1072                 public static long LongCount<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> selector)
1073                 {
1074                         Check.SourceAndSelector (source, selector);
1075
1076                         long counter = 0;
1077                         foreach (TSource element in source)
1078                                 if (selector (element))
1079                                         counter++;
1080
1081                         return counter;
1082                 }
1083
1084                 #endregion
1085
1086                 #region Max
1087
1088                 public static int Max (this IEnumerable<int> source)
1089                 {
1090                         return Iterate (source, int.MinValue, (a, b) => a > b);
1091                 }
1092
1093                 public static long Max (this IEnumerable<long> source)
1094                 {
1095                         return Iterate (source, long.MinValue, (a, b) => a > b);
1096                 }
1097
1098                 public static double Max (this IEnumerable<double> source)
1099                 {
1100                         return Iterate (source, double.MinValue, (a, b) => a > b);
1101                 }
1102
1103                 public static float Max (this IEnumerable<float> source)
1104                 {
1105                         return Iterate (source, float.MinValue, (a, b) => a > b);
1106                 }
1107
1108                 public static decimal Max (this IEnumerable<decimal> source)
1109                 {
1110                         return Iterate (source, decimal.MinValue, (a, b) => a > b);
1111                 }
1112
1113                 static T Iterate<T> (IEnumerable<T> source, T initValue, Func<T, T, bool> selector)
1114                 {
1115                         Check.SourceAndSelector (source, selector);
1116
1117                         int counter = 0;
1118                         foreach (var element in source) {
1119                                 if (selector (element, initValue))
1120                                         initValue = element;
1121                                 ++counter;
1122                         }
1123
1124                         if (counter == 0)
1125                                 throw new InvalidOperationException ();
1126
1127                         return initValue;
1128                 }
1129
1130                 public static int? Max (this IEnumerable<int?> source)
1131                 {
1132                         return IterateNullable (source, int.MinValue, (a, b) => a > b);
1133                 }
1134
1135                 public static long? Max (this IEnumerable<long?> source)
1136                 {
1137                         return IterateNullable (source, long.MinValue, (a, b) => a > b);
1138                 }
1139
1140                 public static double? Max (this IEnumerable<double?> source)
1141                 {
1142                         return IterateNullable (source, double.MinValue, (a, b) => a > b);
1143                 }
1144
1145                 public static float? Max (this IEnumerable<float?> source)
1146                 {
1147                         return IterateNullable (source, float.MinValue, (a, b) => a > b);
1148                 }
1149
1150                 public static decimal? Max (this IEnumerable<decimal?> source)
1151                 {
1152                         return IterateNullable (source, decimal.MinValue, (a, b) => a > b);
1153                 }
1154
1155                 static T? IterateNullable<T> (IEnumerable<T?> source, T initValue, Func<T?, T?, bool> selector) where T : struct
1156                 {
1157                         Check.SourceAndSelector (source, selector);
1158
1159                         int counter = 0;
1160                         T? value = initValue;
1161                         foreach (var element in source) {
1162                                 if (!element.HasValue)
1163                                         continue;
1164
1165                                 if (selector (element.Value, value))
1166                                         value = element;
1167                                 ++counter;
1168                         }
1169
1170                         if (counter == 0)
1171                                 return null;
1172
1173                         return value;
1174                 }
1175
1176                 public static TSource Max<TSource> (this IEnumerable<TSource> source)
1177                 {
1178                         Check.Source (source);
1179
1180                         bool notAssigned = true;
1181                         TSource maximum = default (TSource);
1182                         int counter = 0;
1183                         foreach (TSource element in source) {
1184                                 if (notAssigned) {
1185                                         maximum = element;
1186                                         notAssigned = false;
1187                                 } else {
1188                                         int comparison;
1189                                         if (element is IComparable<TSource>)
1190                                                 comparison = ((IComparable<TSource>) element).CompareTo (maximum);
1191                                         else if (element is System.IComparable)
1192                                                 comparison = ((System.IComparable) element).CompareTo (maximum);
1193                                         else
1194                                                 throw new ArgumentNullException ();
1195
1196                                         if (comparison > 0)
1197                                                 maximum = element;
1198                                 }
1199                                 counter++;
1200                         }
1201
1202                         if (counter == 0)
1203                                 throw new InvalidOperationException ();
1204                         else
1205                                 return maximum;
1206                 }
1207
1208                 public static int Max<TSource> (this IEnumerable<TSource> source, Func<TSource, int> selector)
1209                 {
1210                         return Iterate (source, int.MinValue, (a, b) => {
1211                                 var v = selector (a); return v > b ? v : b;
1212                         });
1213                 }
1214
1215                 public static long Max<TSource> (this IEnumerable<TSource> source, Func<TSource, long> selector)
1216                 {
1217                         return Iterate (source, long.MinValue, (a, b) => {
1218                                 var v = selector (a); return v > b ? v : b;
1219                         });
1220                 }
1221
1222                 public static double Max<TSource> (this IEnumerable<TSource> source, Func<TSource, double> selector)
1223                 {
1224                         return Iterate (source, double.MinValue, (a, b) => {
1225                                 var v = selector (a); return v > b ? v : b;
1226                         });
1227                 }
1228
1229                 public static float Max<TSource> (this IEnumerable<TSource> source, Func<TSource, float> selector)
1230                 {
1231                         return Iterate (source, float.MinValue, (a, b) => {
1232                                 var v = selector (a); return v > b ? v : b;
1233                         });
1234                 }
1235
1236                 public static decimal Max<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal> selector)
1237                 {
1238                         return Iterate (source, decimal.MinValue, (a, b) => {
1239                                 var v = selector (a); return v > b ? v : b;
1240                         });
1241                 }
1242
1243                 static U Iterate<T, U> (IEnumerable<T> source, U initValue, Func<T, U, U> selector)
1244                 {
1245                         Check.SourceAndSelector (source, selector);
1246
1247                         int counter = 0;
1248                         foreach (var element in source) {
1249                                 initValue = selector (element, initValue);
1250                                 ++counter;
1251                         }
1252
1253                         if (counter == 0)
1254                                 throw new InvalidOperationException ();
1255
1256                         return initValue;
1257                 }
1258
1259                 static U? IterateNullable<T, U> (IEnumerable<T> source, U initialValue, Func<T, U?, U?> selector) where U : struct
1260                 {
1261                         Check.SourceAndSelector (source, selector);
1262
1263                         int counter = 0;
1264                         U? value = initialValue;
1265                         foreach (var element in source) {
1266                                 value = selector (element, value);
1267                                 if (!value.HasValue)
1268                                         continue;
1269
1270                                 ++counter;
1271                         }
1272
1273                         if (counter == 0)
1274                                 return null;
1275
1276                         return value;
1277                 }
1278
1279                 public static int? Max<TSource> (this IEnumerable<TSource> source, Func<TSource, int?> selector)
1280                 {
1281                         return IterateNullable (source, int.MinValue, (a, b) => {
1282                                 var v = selector (a); return v > b ? v : b;
1283                         });
1284                 }
1285
1286                 public static long? Max<TSource> (this IEnumerable<TSource> source, Func<TSource, long?> selector)
1287                 {
1288                         return IterateNullable (source, long.MinValue, (a, b) => {
1289                                 var v = selector (a); return v > b ? v : b;
1290                         });
1291                 }
1292
1293                 public static double? Max<TSource> (this IEnumerable<TSource> source, Func<TSource, double?> selector)
1294                 {
1295                         return IterateNullable (source, double.MinValue, (a, b) => {
1296                                 var v = selector (a); return v > b ? v : b;
1297                         });
1298                 }
1299
1300                 public static float? Max<TSource> (this IEnumerable<TSource> source, Func<TSource, float?> selector)
1301                 {
1302                         return IterateNullable (source, float.MinValue, (a, b) => {
1303                                 var v = selector (a); return v > b ? v : b;
1304                         });
1305                 }
1306
1307                 public static decimal? Max<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
1308                 {
1309                         return IterateNullable (source, decimal.MinValue, (a, b) => {
1310                                 var v = selector (a); return v > b ? v : b;
1311                         });
1312                 }
1313
1314                 public static TResult Max<TSource, TResult> (this IEnumerable<TSource> source,
1315                                 Func<TSource, TResult> selector)
1316                 {
1317                         Check.SourceAndSelector (source, selector);
1318
1319                         bool notAssigned = true;
1320                         TResult maximum = default (TResult);
1321                         int counter = 0;
1322                         foreach (TSource item in source) {
1323                                 TResult element = selector (item);
1324                                 if (notAssigned) {
1325                                         maximum = element;
1326                                         notAssigned = false;
1327                                 } else {
1328                                         int comparison;
1329                                         if (element is IComparable<TResult>)
1330                                                 comparison = ((IComparable<TResult>) element).CompareTo (maximum);
1331                                         else if (element is System.IComparable)
1332                                                 comparison = ((System.IComparable) element).CompareTo (maximum);
1333                                         else
1334                                                 throw new ArgumentNullException ();
1335
1336                                         if (comparison > 0)
1337                                                 maximum = element;
1338                                 }
1339                                 counter++;
1340                         }
1341
1342                         if (counter == 0)
1343                                 throw new InvalidOperationException ();
1344                         else
1345                                 return maximum;
1346                 }
1347
1348                 #endregion
1349
1350                 #region Min
1351
1352                 public static int Min (this IEnumerable<int> source)
1353                 {
1354                         return Iterate (source, int.MaxValue, (a, b) => a < b);
1355                 }
1356
1357                 public static long Min (this IEnumerable<long> source)
1358                 {
1359                         return Iterate (source, long.MaxValue, (a, b) => a < b);
1360                 }
1361
1362                 public static double Min (this IEnumerable<double> source)
1363                 {
1364                         return Iterate (source, double.MaxValue, (a, b) => a < b);
1365                 }
1366
1367                 public static float Min (this IEnumerable<float> source)
1368                 {
1369                         return Iterate (source, float.MaxValue, (a, b) => a < b);
1370                 }
1371
1372                 public static decimal Min (this IEnumerable<decimal> source)
1373                 {
1374                         return Iterate (source, decimal.MaxValue, (a, b) => a < b);
1375                 }
1376
1377                 public static int? Min (this IEnumerable<int?> source)
1378                 {
1379                         return IterateNullable (source, int.MaxValue, (a, b) => a < b);
1380                 }
1381
1382                 public static long? Min (this IEnumerable<long?> source)
1383                 {
1384                         return IterateNullable (source, long.MaxValue, (a, b) => a < b);
1385                 }
1386
1387                 public static double? Min (this IEnumerable<double?> source)
1388                 {
1389                         return IterateNullable (source, double.MaxValue, (a, b) => a < b);
1390                 }
1391
1392                 public static float? Min (this IEnumerable<float?> source)
1393                 {
1394                         return IterateNullable (source, float.MaxValue, (a, b) => a < b);
1395                 }
1396
1397                 public static decimal? Min (this IEnumerable<decimal?> source)
1398                 {
1399                         return IterateNullable (source, decimal.MaxValue, (a, b) => a < b);
1400                 }
1401
1402                 public static TSource Min<TSource> (this IEnumerable<TSource> source)
1403                 {
1404                         Check.Source (source);
1405
1406                         bool notAssigned = true;
1407                         TSource minimum = default (TSource);
1408                         int counter = 0;
1409                         foreach (TSource element in source) {
1410                                 if (notAssigned) {
1411                                         minimum = element;
1412                                         notAssigned = false;
1413                                 } else {
1414                                         int comparison;
1415                                         if (element is IComparable<TSource>)
1416                                                 comparison = ((IComparable<TSource>) element).CompareTo (minimum);
1417                                         else if (element is System.IComparable)
1418                                                 comparison = ((System.IComparable) element).CompareTo (minimum);
1419                                         else
1420                                                 throw new ArgumentNullException ();
1421
1422                                         if (comparison < 0)
1423                                                 minimum = element;
1424                                 }
1425                                 counter++;
1426                         }
1427
1428                         if (counter == 0)
1429                                 throw new InvalidOperationException ();
1430                         else
1431                                 return minimum;
1432                 }
1433
1434                 public static int Min<TSource> (this IEnumerable<TSource> source, Func<TSource, int> selector)
1435                 {
1436                         return Iterate (source, int.MaxValue, (a, b) => {
1437                                 var v = selector (a); return v < b ? v : b;
1438                         });
1439                 }
1440
1441                 public static long Min<TSource> (this IEnumerable<TSource> source, Func<TSource, long> selector)
1442                 {
1443                         return Iterate (source, long.MaxValue, (a, b) => {
1444                                 var v = selector (a); return v < b ? v : b;
1445                         });
1446                 }
1447
1448                 public static double Min<TSource> (this IEnumerable<TSource> source, Func<TSource, double> selector)
1449                 {
1450                         return Iterate (source, double.MaxValue, (a, b) => {
1451                                 var v = selector (a); return v < b ? v : b;
1452                         });
1453                 }
1454
1455                 public static float Min<TSource> (this IEnumerable<TSource> source, Func<TSource, float> selector)
1456                 {
1457                         return Iterate (source, float.MaxValue, (a, b) => {
1458                                 var v = selector (a); return v < b ? v : b;
1459                         });
1460                 }
1461
1462                 public static decimal Min<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal> selector)
1463                 {
1464                         return Iterate (source, decimal.MaxValue, (a, b) => {
1465                                 var v = selector (a); return v < b ? v : b;
1466                         });
1467                 }
1468
1469                 public static int? Min<TSource> (this IEnumerable<TSource> source, Func<TSource, int?> selector)
1470                 {
1471                         return IterateNullable (source, int.MaxValue, (a, b) => {
1472                                 var v = selector (a); return v < b ? v : b;
1473                         });
1474                 }
1475
1476                 public static long? Min<TSource> (this IEnumerable<TSource> source, Func<TSource, long?> selector)
1477                 {
1478                         return IterateNullable (source, long.MaxValue, (a, b) => {
1479                                 var v = selector (a); return v < b ? v : b;
1480                         });
1481                 }
1482
1483                 public static double? Min<TSource> (this IEnumerable<TSource> source, Func<TSource, float?> selector)
1484                 {
1485                         return IterateNullable (source, float.MaxValue, (a, b) => {
1486                                 var v = selector (a); return v < b ? v : b;
1487                         });
1488                 }
1489
1490                 public static double? Min<TSource> (this IEnumerable<TSource> source, Func<TSource, double?> selector)
1491                 {
1492                         return IterateNullable (source, double.MaxValue, (a, b) => {
1493                                 var v = selector (a); return v < b ? v : b;
1494                         });
1495                 }
1496
1497                 public static decimal? Min<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
1498                 {
1499                         return IterateNullable (source, decimal.MaxValue, (a, b) => {
1500                                 var v = selector (a); return v < b ? v : b;
1501                         });
1502                 }
1503
1504                 public static TResult Min<TSource, TResult> (this IEnumerable<TSource> source,
1505                                 Func<TSource, TResult> selector)
1506                 {
1507                         Check.SourceAndSelector (source, selector);
1508
1509                         bool notAssigned = true;
1510                         TResult minimum = default (TResult);
1511                         int counter = 0;
1512                         foreach (TSource item in source) {
1513                                 TResult element = selector (item);
1514                                 if (notAssigned) {
1515                                         minimum = element;
1516                                         notAssigned = false;
1517                                 } else {
1518                                         int comparison;
1519                                         if (element is IComparable<TResult>)
1520                                                 comparison = ((IComparable<TResult>) element).CompareTo (minimum);
1521                                         else if (element is System.IComparable)
1522                                                 comparison = ((System.IComparable) element).CompareTo (minimum);
1523                                         else
1524                                                 throw new ArgumentNullException ();
1525
1526                                         if (comparison < 0)
1527                                                 minimum = element;
1528                                 }
1529                                 counter++;
1530                         }
1531
1532                         if (counter == 0)
1533                                 throw new InvalidOperationException ();
1534                         else
1535                                 return minimum;
1536                 }
1537
1538                 #endregion
1539
1540                 #region OfType
1541
1542                 public static IEnumerable<TResult> OfType<TResult> (this IEnumerable source)
1543                 {
1544                         Check.Source (source);
1545
1546                         return CreateOfTypeIterator<TResult> (source);
1547                 }
1548
1549                 static IEnumerable<TResult> CreateOfTypeIterator<TResult> (IEnumerable source)
1550                 {
1551                         foreach (object element in source)
1552                                 if (element is TResult)
1553                                         yield return (TResult) element;
1554                 }
1555
1556                 #endregion
1557
1558                 #region OrderBy
1559
1560                 public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey> (this IEnumerable<TSource> source,
1561                                 Func<TSource, TKey> keySelector)
1562                 {
1563                         return OrderBy<TSource, TKey> (source, keySelector, null);
1564                 }
1565
1566
1567                 public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey> (this IEnumerable<TSource> source,
1568                                 Func<TSource, TKey> keySelector,
1569                                 IComparer<TKey> comparer)
1570                 {
1571                         Check.SourceAndKeySelector (source, keySelector);
1572
1573                         return new InternalOrderedSequence<TSource, TKey> (
1574                                         source, keySelector, comparer, false);
1575                 }
1576
1577                 #endregion
1578
1579                 #region OrderByDescending
1580
1581                 public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey> (this IEnumerable<TSource> source,
1582                                 Func<TSource, TKey> keySelector)
1583                 {
1584                         return OrderByDescending<TSource, TKey> (source, keySelector, null);
1585                 }
1586
1587
1588                 public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey> (this IEnumerable<TSource> source,
1589                                 Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
1590                 {
1591                         Check.SourceAndKeySelector (source, keySelector);
1592
1593                         return new InternalOrderedSequence<TSource, TKey> (
1594                                         source, keySelector, comparer, true);
1595                 }
1596
1597                 #endregion
1598
1599                 #region Range
1600
1601                 public static IEnumerable<int> Range (int start, int count)
1602                 {
1603                         if (count < 0)
1604                                 throw new ArgumentOutOfRangeException ("count");
1605
1606                         long upto = ((long) start + count) - 1;
1607
1608                         if (upto > int.MaxValue)
1609                                 throw new ArgumentOutOfRangeException ();
1610
1611                         return CreateRangeIterator (start, (int) upto);
1612                 }
1613
1614                 static IEnumerable<int> CreateRangeIterator (int start, int upto)
1615                 {
1616                         for (int i = start; i <= upto; i++)
1617                                 yield return i;
1618                 }
1619
1620                 #endregion
1621
1622                 #region Repeat
1623
1624                 public static IEnumerable<TResult> Repeat<TResult> (TResult element, int count)
1625                 {
1626                         if (count < 0)
1627                                 throw new ArgumentOutOfRangeException ();
1628
1629                         return CreateRepeatIterator (element, count);
1630                 }
1631
1632                 static IEnumerable<TResult> CreateRepeatIterator<TResult> (TResult element, int count)
1633                 {
1634                         for (int i = 0; i < count; i++)
1635                                 yield return element;
1636                 }
1637
1638                 #endregion
1639
1640
1641                 #region Reverse
1642
1643                 public static IEnumerable<TSource> Reverse<TSource> (this IEnumerable<TSource> source)
1644                 {
1645                         Check.Source (source);
1646
1647                         return CreateReverseIterator (source);
1648                 }
1649
1650                 static IEnumerable<TSource> CreateReverseIterator<TSource> (IEnumerable<TSource> source)
1651                 {
1652                         var list = new List<TSource> (source);
1653                         list.Reverse ();
1654                         return list;
1655                 }
1656
1657                 #endregion
1658
1659                 #region Select
1660
1661                 public static IEnumerable<TResult> Select<TSource, TResult> (this IEnumerable<TSource> source, Func<TSource, TResult> selector)
1662                 {
1663                         Check.SourceAndSelector (source, selector);
1664
1665                         return CreateSelectIterator (source, selector);
1666                 }
1667
1668                 static IEnumerable<TResult> CreateSelectIterator<TSource, TResult> (IEnumerable<TSource> source, Func<TSource, TResult> selector)
1669                 {
1670                         foreach (TSource element in source)
1671                                 yield return selector (element);
1672                 }
1673
1674                 public static IEnumerable<TResult> Select<TSource, TResult> (this IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
1675                 {
1676                         Check.SourceAndSelector (source, selector);
1677
1678                         return CreateSelectIterator (source, selector);
1679                 }
1680
1681                 static IEnumerable<TResult> CreateSelectIterator<TSource, TResult> (IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
1682                 {
1683                         int counter = 0;
1684                         foreach (TSource element in source) {
1685                                 yield return selector (element, counter);
1686                                 counter++;
1687                         }
1688                 }
1689
1690                 #endregion
1691
1692                 #region SelectMany
1693
1694                 public static IEnumerable<TResult> SelectMany<TSource, TResult> (this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
1695                 {
1696                         Check.SourceAndSelector (source, selector);
1697
1698                         return CreateSelectManyIterator (source, selector);
1699                 }
1700
1701                 static IEnumerable<TResult> CreateSelectManyIterator<TSource, TResult> (IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
1702                 {
1703                         foreach (TSource element in source)
1704                                 foreach (TResult item in selector (element))
1705                                         yield return item;
1706                 }
1707
1708                 public static IEnumerable<TResult> SelectMany<TSource, TResult> (this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TResult>> selector)
1709                 {
1710                         Check.SourceAndSelector (source, selector);
1711
1712                         return CreateSelectManyIterator (source, selector);
1713                 }
1714
1715                 static IEnumerable<TResult> CreateSelectManyIterator<TSource, TResult> (IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TResult>> selector)
1716                 {
1717                         int counter = 0;
1718                         foreach (TSource element in source) {
1719                                 foreach (TResult item in selector (element, counter++))
1720                                         yield return item;
1721                                 counter++;
1722                         }
1723                 }
1724
1725                 public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult> (this IEnumerable<TSource> source,
1726                         Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> selector)
1727                 {
1728                         Check.SourceAndCollectionSelectors (source, collectionSelector, selector);
1729
1730                         return CreateSelectManyIterator (source, collectionSelector, selector);
1731                 }
1732
1733                 static IEnumerable<TResult> CreateSelectManyIterator<TSource, TCollection, TResult> (IEnumerable<TSource> source,
1734                         Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> selector)
1735                 {
1736                         foreach (TSource element in source)
1737                                 foreach (TCollection collection in collectionSelector (element))
1738                                         yield return selector (element, collection);
1739                 }
1740
1741                 public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult> (this IEnumerable<TSource> source,
1742                         Func<TSource, int, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> selector)
1743                 {
1744                         Check.SourceAndCollectionSelectors (source, collectionSelector, selector);
1745
1746                         return CreateSelectManyIterator (source, collectionSelector, selector);
1747                 }
1748
1749                 static IEnumerable<TResult> CreateSelectManyIterator<TSource, TCollection, TResult> (IEnumerable<TSource> source,
1750                         Func<TSource, int, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> selector)
1751                 {
1752                         int counter = 0;
1753                         foreach (TSource element in source)
1754                                 foreach (TCollection collection in collectionSelector (element, counter++))
1755                                         yield return selector (element, collection);
1756                 }
1757
1758                 #endregion
1759
1760                 #region Single
1761
1762                 public static TSource Single<TSource> (this IEnumerable<TSource> source)
1763                 {
1764                         Check.Source (source);
1765
1766                         bool otherElement = false;
1767                         TSource singleElement = default (TSource);
1768                         foreach (TSource element in source) {
1769                                 if (otherElement) throw new InvalidOperationException ();
1770                                 if (!otherElement) otherElement = true;
1771                                 singleElement = element;
1772                         }
1773
1774                         if (otherElement)
1775                                 return singleElement;
1776                         else
1777                                 throw new InvalidOperationException ();
1778                 }
1779
1780
1781                 public static TSource Single<TSource> (this IEnumerable<TSource> source,
1782                                 Func<TSource, bool> predicate)
1783                 {
1784                         Check.SourceAndPredicate (source, predicate);
1785
1786                         bool otherElement = false;
1787                         TSource singleElement = default (TSource);
1788                         foreach (TSource element in source) {
1789                                 if (predicate (element)) {
1790                                         if (otherElement) throw new InvalidOperationException ();
1791                                         if (!otherElement) otherElement = true;
1792                                         singleElement = element;
1793                                 }
1794                         }
1795
1796                         if (otherElement)
1797                                 return singleElement;
1798                         else
1799                                 throw new InvalidOperationException ();
1800                 }
1801
1802                 #endregion
1803
1804                 #region SingleOrDefault
1805
1806                 public static TSource SingleOrDefault<TSource> (this IEnumerable<TSource> source)
1807                 {
1808                         Check.Source (source);
1809
1810                         bool otherElement = false;
1811                         TSource singleElement = default (TSource);
1812                         foreach (TSource element in source) {
1813                                 if (otherElement) throw new InvalidOperationException ();
1814                                 if (!otherElement) otherElement = true;
1815                                 singleElement = element;
1816                         }
1817
1818                         return singleElement;
1819                 }
1820
1821
1822                 public static TSource SingleOrDefault<TSource> (this IEnumerable<TSource> source,
1823                                 Func<TSource, bool> predicate)
1824                 {
1825                         Check.SourceAndPredicate (source, predicate);
1826
1827                         bool otherElement = false;
1828                         TSource singleElement = default (TSource);
1829                         foreach (TSource element in source) {
1830                                 if (predicate (element)) {
1831                                         if (otherElement) throw new InvalidOperationException ();
1832                                         if (!otherElement) otherElement = true;
1833                                         singleElement = element;
1834                                 }
1835                         }
1836
1837                         return singleElement;
1838                 }
1839
1840                 #endregion
1841
1842                 #region Skip
1843
1844                 public static IEnumerable<TSource> Skip<TSource> (this IEnumerable<TSource> source, int count)
1845                 {
1846                         Check.Source (source);
1847
1848                         return CreateSkipIterator (source, count);
1849                 }
1850
1851                 static IEnumerable<TSource> CreateSkipIterator<TSource> (IEnumerable<TSource> source, int count)
1852                 {
1853                         int i = 0;
1854                         foreach (var element in source) {
1855                                 if (i++ < count)
1856                                         continue;
1857
1858                                 yield return element;
1859                         }
1860                 }
1861
1862                 #endregion
1863
1864                 #region SkipWhile
1865
1866                 public static IEnumerable<TSource> SkipWhile<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
1867                 {
1868                         Check.SourceAndPredicate (source, predicate);
1869
1870                         return CreateSkipWhileIterator (source, predicate);
1871                 }
1872
1873                 static IEnumerable<TSource> CreateSkipWhileIterator<TSource> (IEnumerable<TSource> source, Func<TSource, bool> predicate)
1874                 {
1875                         bool yield = false;
1876
1877                         foreach (TSource element in source) {
1878                                 if (yield)
1879                                         yield return element;
1880                                 else
1881                                         if (!predicate (element)) {
1882                                                 yield return element;
1883                                                 yield = true;
1884                                         }
1885                         }
1886                 }
1887
1888                 public static IEnumerable<TSource> SkipWhile<TSource> (this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
1889                 {
1890                         Check.SourceAndPredicate (source, predicate);
1891
1892                         return CreateSkipWhileIterator (source, predicate);
1893                 }
1894
1895                 static IEnumerable<TSource> CreateSkipWhileIterator<TSource> (IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
1896                 {
1897                         int counter = 0;
1898                         bool yield = false;
1899
1900                         foreach (TSource element in source) {
1901                                 if (yield)
1902                                         yield return element;
1903                                 else
1904                                         if (!predicate (element, counter)) {
1905                                                 yield return element;
1906                                                 yield = true;
1907                                         }
1908                                 counter++;
1909                         }
1910                 }
1911
1912                 #endregion
1913
1914                 #region Sum
1915
1916                 public static int Sum (this IEnumerable<int> source)
1917                 {
1918                         return Sum<int, int> (source, (a, b) => a + b);
1919                 }
1920
1921                 public static int? Sum (this IEnumerable<int?> source)
1922                 {
1923                         return SumNullable<int?, int?> (source, (a, b) => a.HasValue ? a + b : a);
1924                 }
1925
1926                 public static int Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, int> selector)
1927                 {
1928                         return Sum<TSource, int> (source, (a, b) => a + selector (b));
1929                 }
1930
1931                 public static int? Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, int?> selector)
1932                 {
1933                         return SumNullable<TSource, int?> (source, (a, b) => {
1934                                 var value = selector (b);
1935                                 return value.HasValue ? a + value.Value : a;
1936                         });
1937                 }
1938
1939                 public static long Sum (this IEnumerable<long> source)
1940                 {
1941                         return Sum<long, long> (source, (a, b) => a + b);
1942                 }
1943
1944                 public static long? Sum (this IEnumerable<long?> source)
1945                 {
1946                         return SumNullable<long?, long?> (source, (a, b) => a.HasValue ? a + b : a);
1947                 }
1948
1949                 public static long Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, long> selector)
1950                 {
1951                         return Sum<TSource, long> (source, (a, b) => a + selector (b));
1952                 }
1953
1954                 public static long? Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, long?> selector)
1955                 {
1956                         return SumNullable<TSource, long?> (source, (a, b) => {
1957                                 var value = selector (b);
1958                                 return value.HasValue ? a + value.Value : a;
1959                         });
1960                 }
1961
1962                 public static double Sum (this IEnumerable<double> source)
1963                 {
1964                         return Sum<double, double> (source, (a, b) => a + b);
1965                 }
1966
1967                 public static double? Sum (this IEnumerable<double?> source)
1968                 {
1969                         return SumNullable<double?, double?> (source, (a, b) => a.HasValue ? a + b : a);
1970                 }
1971
1972                 public static double Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, double> selector)
1973                 {
1974                         return Sum<TSource, double> (source, (a, b) => a + selector (b));
1975                 }
1976
1977                 public static double? Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, double?> selector)
1978                 {
1979                         return SumNullable<TSource, double?> (source, (a, b) => {
1980                                 var value = selector (b);
1981                                 return value.HasValue ? a + value.Value : a;
1982                         });
1983                 }
1984
1985                 public static float Sum (this IEnumerable<float> source)
1986                 {
1987                         return Sum<float, float> (source, (a, b) => a + b);
1988                 }
1989
1990                 public static float? Sum (this IEnumerable<float?> source)
1991                 {
1992                         return SumNullable<float?, float?> (source, (a, b) => a.HasValue ? a + b : a);
1993                 }
1994
1995                 public static float Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, float> selector)
1996                 {
1997                         return Sum<TSource, float> (source, (a, b) => a + selector (b));
1998                 }
1999
2000                 public static float? Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, float?> selector)
2001                 {
2002                         return SumNullable<TSource, float?> (source, (a, b) => {
2003                                 var value = selector (b);
2004                                 return value.HasValue ? a + value.Value : a;
2005                         });
2006                 }
2007
2008                 public static decimal Sum (this IEnumerable<decimal> source)
2009                 {
2010                         return Sum<decimal, decimal> (source, (a, b) => a + b);
2011                 }
2012
2013                 public static decimal? Sum (this IEnumerable<decimal?> source)
2014                 {
2015                         return SumNullable<decimal?, decimal?> (source, (a, b) => a.HasValue ? a + b : a);
2016                 }
2017
2018                 public static decimal Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal> selector)
2019                 {
2020                         return Sum<TSource, decimal> (source, (a, b) => a + selector (b));
2021                 }
2022
2023                 public static decimal? Sum<TSource> (this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
2024                 {
2025                         return SumNullable<TSource, decimal?> (source, (a, b) => {
2026                                 var value = selector (b);
2027                                 return value.HasValue ? a + value.Value : a;
2028                         });
2029                 }
2030
2031                 static TR Sum<TA, TR> (this IEnumerable<TA> source, Func<TR, TA, TR> func)
2032                 {
2033                         Check.Source (source);
2034
2035                         TR total = default (TR);
2036                         int counter = 0;
2037                         foreach (var element in source) {
2038                                 total = func (total, element);
2039                                 ++counter;
2040                         }
2041
2042                         if (counter == 0)
2043                                 throw new InvalidOperationException ();
2044
2045                         return total;
2046                 }
2047
2048                 static TR SumNullable<TA, TR> (this IEnumerable<TA> source, Func<TR, TA, TR> func)
2049                 {
2050                         Check.Source (source);
2051
2052                         TR total = default (TR);
2053                         foreach (var element in source) {
2054                                 total = func (total, element);
2055                         }
2056
2057                         return total;
2058                 }
2059
2060                 #endregion
2061
2062                 #region Take
2063
2064                 public static IEnumerable<TSource> Take<TSource> (this IEnumerable<TSource> source, int count)
2065                 {
2066                         Check.Source (source);
2067
2068                         return CreateTakeIterator (source, count);
2069                 }
2070
2071                 static IEnumerable<TSource> CreateTakeIterator<TSource> (IEnumerable<TSource> source, int count)
2072                 {
2073                         if (count <= 0)
2074                                 yield break;
2075
2076                         int counter = 0;
2077                         foreach (TSource element in source) {
2078                                 if (counter++ == count)
2079                                         yield break;
2080
2081                                 yield return element;
2082                         }
2083                 }
2084
2085                 #endregion
2086
2087                 #region TakeWhile
2088
2089                 public static IEnumerable<TSource> TakeWhile<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
2090                 {
2091                         Check.SourceAndPredicate (source, predicate);
2092
2093                         return CreateTakeWhileIterator (source, predicate);
2094                 }
2095
2096                 static IEnumerable<TSource> CreateTakeWhileIterator<TSource> (IEnumerable<TSource> source, Func<TSource, bool> predicate)
2097                 {
2098                         foreach (TSource element in source) {
2099                                 if (!predicate (element))
2100                                         yield break;
2101
2102                                 yield return element;
2103                         }
2104                 }
2105
2106                 public static IEnumerable<TSource> TakeWhile<TSource> (this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
2107                 {
2108                         Check.SourceAndPredicate (source, predicate);
2109
2110                         return CreateTakeWhileIterator (source, predicate);
2111                 }
2112
2113                 static IEnumerable<TSource> CreateTakeWhileIterator<TSource> (IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
2114                 {
2115                         int counter = 0;
2116                         foreach (var element in source) {
2117                                 if (!predicate (element, counter))
2118                                         yield break;
2119
2120                                 yield return element;
2121                                 counter++;
2122                         }
2123                 }
2124
2125                 #endregion
2126
2127                 #region ThenBy
2128
2129                 public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey> (this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector)
2130                 {
2131                         return ThenBy<TSource, TKey> (source, keySelector, null);
2132                 }
2133
2134
2135                 public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey> (this IOrderedEnumerable<TSource> source,
2136                         Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
2137                 {
2138                         Check.SourceAndKeySelector (source, keySelector);
2139
2140                         return source.CreateOrderedEnumerable (keySelector, comparer, false);
2141                 }
2142
2143                 #endregion
2144
2145                 #region ThenByDescending
2146
2147                 public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey> (this IOrderedEnumerable<TSource> source,
2148                         Func<TSource, TKey> keySelector)
2149                 {
2150                         return ThenByDescending<TSource, TKey> (source, keySelector, null);
2151                 }
2152
2153
2154                 public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey> (this IOrderedEnumerable<TSource> source,
2155                         Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
2156                 {
2157                         Check.SourceAndKeySelector (source, keySelector);
2158
2159                         return source.CreateOrderedEnumerable (keySelector, comparer, true);
2160                 }
2161
2162                 #endregion
2163
2164                 #region ToArray
2165                 public static TSource [] ToArray<TSource> (this IEnumerable<TSource> source)
2166                 {
2167                         Check.Source (source);
2168
2169                         List<TSource> list = new List<TSource> (source);
2170                         return list.ToArray ();
2171                 }
2172
2173                 #endregion
2174
2175                 #region ToDictionary
2176                 public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement> (this IEnumerable<TSource> source,
2177                                 Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
2178                 {
2179                         return ToDictionary<TSource, TKey, TElement> (source, keySelector, elementSelector, null);
2180                 }
2181
2182                 public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement> (this IEnumerable<TSource> source,
2183                                 Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
2184                 {
2185                         Check.SourceAndKeyElementSelectors (source, keySelector, elementSelector);
2186
2187                         var dict = new Dictionary<TKey, TElement> (comparer);
2188                         foreach (var e in source)
2189                                 dict.Add (keySelector (e), elementSelector (e));
2190
2191                         return dict;
2192                 }
2193
2194                 public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey> (this IEnumerable<TSource> source,
2195                                 Func<TSource, TKey> keySelector)
2196                 {
2197                         return ToDictionary (source, keySelector, null);
2198                 }
2199
2200                 public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey> (this IEnumerable<TSource> source,
2201                                 Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
2202                 {
2203                         throw new NotImplementedException ();
2204                         // FIXME: compiler issue
2205                         //return ToDictionary (source, keySelector, (a) => a, comparer);
2206                 }
2207
2208                 #endregion
2209
2210                 #region ToList
2211                 public static List<TSource> ToList<TSource> (this IEnumerable<TSource> source)
2212                 {
2213                         Check.Source (source);
2214
2215                         return new List<TSource> (source);
2216                 }
2217                 #endregion
2218
2219                 #region ToLookup
2220
2221                 public static ILookup<TKey, TSource> ToLookup<TSource, TKey> (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
2222                 {
2223                         return ToLookup<TSource, TKey> (source, keySelector, null);
2224                 }
2225
2226                 public static ILookup<TKey, TSource> ToLookup<TSource, TKey> (this IEnumerable<TSource> source,
2227                         Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
2228                 {
2229                         Check.SourceAndKeySelector (source, keySelector);
2230
2231                         var dictionary = new Dictionary<TKey, List<TSource>> (comparer ?? EqualityComparer<TKey>.Default);
2232                         foreach (TSource element in source) {
2233                                 TKey key = keySelector (element);
2234                                 if (key == null)
2235                                         throw new ArgumentNullException ();
2236                                 if (!dictionary.ContainsKey (key))
2237                                         dictionary.Add (key, new List<TSource> ());
2238                                 dictionary [key].Add (element);
2239                         }
2240                         return new Lookup<TKey, TSource> (dictionary);
2241                 }
2242
2243                 public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement> (this IEnumerable<TSource> source,
2244                         Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
2245                 {
2246                         return ToLookup<TSource, TKey, TElement> (source, keySelector, elementSelector, null);
2247                 }
2248
2249                 public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement> (this IEnumerable<TSource> source,
2250                         Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
2251                 {
2252                         Check.SourceAndKeyElementSelectors (source, keySelector, elementSelector);
2253
2254                         Dictionary<TKey, List<TElement>> dictionary = new Dictionary<TKey, List<TElement>> (comparer ?? EqualityComparer<TKey>.Default);
2255                         foreach (TSource element in source) {
2256                                 TKey key = keySelector (element);
2257                                 if (key == null)
2258                                         throw new ArgumentNullException ();
2259                                 if (!dictionary.ContainsKey (key))
2260                                         dictionary.Add (key, new List<TElement> ());
2261                                 dictionary [key].Add (elementSelector (element));
2262                         }
2263                         return new Lookup<TKey, TElement> (dictionary);
2264                 }
2265
2266                 #endregion
2267
2268                 #region SequenceEqual
2269
2270                 public static bool SequenceEqual<TSource> (this IEnumerable<TSource> first, IEnumerable<TSource> second)
2271                 {
2272                         return first.SequenceEqual (second, null);
2273                 }
2274
2275                 public static bool SequenceEqual<TSource> (this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
2276                 {
2277                         Check.FirstAndSecond (first, second);
2278
2279                         if (comparer == null)
2280                                 comparer = EqualityComparer<TSource>.Default;
2281
2282                         var first_enumerator = first.GetEnumerator ();
2283                         var second_enumerator = second.GetEnumerator ();
2284
2285                         while (first_enumerator.MoveNext ()) {
2286                                 if (!second_enumerator.MoveNext ())
2287                                         return false;
2288
2289                                 if (!comparer.Equals (first_enumerator.Current, second_enumerator.Current))
2290                                         return false;
2291                         }
2292
2293                         return !second_enumerator.MoveNext ();
2294                 }
2295
2296                 #endregion
2297
2298                 #region Union
2299
2300                 public static IEnumerable<TSource> Union<TSource> (this IEnumerable<TSource> first, IEnumerable<TSource> second)
2301                 {
2302                         Check.FirstAndSecond (first, second);
2303
2304                         return first.Union (second, null);
2305                 }
2306
2307                 public static IEnumerable<TSource> Union<TSource> (this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
2308                 {
2309                         Check.FirstAndSecond (first, second);
2310
2311                         if (comparer == null)
2312                                 comparer = EqualityComparer<TSource>.Default;
2313
2314                         return CreateUnionIterator (first, second, comparer);
2315                 }
2316
2317                 static IEnumerable<TSource> CreateUnionIterator<TSource> (IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
2318                 {
2319                         var items = new HashSet<TSource> ();
2320                         foreach (var element in first) {
2321                                 if (! items.Contains (element, comparer)) {
2322                                         items.Add (element);
2323                                         yield return element;
2324                                 }
2325                         }
2326
2327                         foreach (var element in second) {
2328                                 if (! items.Contains (element, comparer)) {
2329                                         items.Add (element);
2330                                         yield return element;
2331                                 }
2332                         }
2333                 }
2334
2335                 #endregion
2336
2337                 #region Where
2338
2339                 public static IEnumerable<TSource> Where<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate)
2340                 {
2341                         Check.SourceAndPredicate (source, predicate);
2342
2343                         return CreateWhereIterator (source, predicate);
2344                 }
2345
2346                 static IEnumerable<TSource> CreateWhereIterator<TSource> (IEnumerable<TSource> source, Func<TSource, bool> predicate)
2347                 {
2348                         foreach (TSource element in source)
2349                                 if (predicate (element))
2350                                         yield return element;
2351                 }
2352
2353                 public static IEnumerable<TSource> Where<TSource> (this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
2354                 {
2355                         Check.SourceAndPredicate (source, predicate);
2356
2357                         return CreateWhereIterator (source, predicate);
2358                 }
2359
2360                 static IEnumerable<TSource> CreateWhereIterator<TSource> (this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
2361                 {
2362                         int counter = 0;
2363                         foreach (TSource element in source) {
2364                                 if (predicate (element, counter))
2365                                         yield return element;
2366                                 counter++;
2367                         }
2368                 }
2369
2370                 #endregion
2371
2372                 internal static ReadOnlyCollection<TSource> ToReadOnlyCollection<TSource> (this IEnumerable<TSource> source)
2373                 {
2374                         if (source == null)
2375                                 return new ReadOnlyCollection<TSource> (new TSource [0]); // could we singlotenize that?
2376
2377                         var ro = source as ReadOnlyCollection<TSource>;
2378                         if (ro != null)
2379                                 return ro;
2380
2381                         return new ReadOnlyCollection<TSource> (source.ToArray<TSource> ());
2382                 }
2383         }
2384 }