PageRenderTime 60ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/System.Core/System.Linq/Enumerable.cs

https://bitbucket.org/cosi2/dotnetanywhere-wb
C# | 1405 lines | 1098 code | 269 blank | 38 comment | 92 complexity | cf4c6f600d17d38f2b5a875686cb3782 MD5 | raw file
  1. // Copyright (c) 2009 DotNetAnywhere
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. using System;
  21. using System.Collections.Generic;
  22. using System.Linq;
  23. using System.Text;
  24. using System.Collections;
  25. namespace System.Linq {
  26. public static class Enumerable {
  27. private static class Funcs<T> {
  28. public static readonly Func<T, bool> True = x => true;
  29. public static readonly Func<T, T> Identity = x => x;
  30. }
  31. #region Aggregate
  32. public static T Aggregate<T>(this IEnumerable<T> source, Func<T, T, T> func) {
  33. Check(source, func);
  34. using (var en = source.GetEnumerator()) {
  35. if (!en.MoveNext()) {
  36. throw new InvalidOperationException();
  37. }
  38. T value = en.Current;
  39. while (en.MoveNext()) {
  40. value = func(value, en.Current);
  41. }
  42. return value;
  43. }
  44. }
  45. public static TAcc Aggregate<T, TAcc>(this IEnumerable<T> source, TAcc seed, Func<TAcc, T, TAcc> func) {
  46. return source.Aggregate(seed, func, Funcs<TAcc>.Identity);
  47. }
  48. public static TResult Aggregate<T, TAcc, TResult>
  49. (this IEnumerable<T> source, TAcc seed, Func<TAcc, T, TAcc> func, Func<TAcc,TResult> resultSelector) {
  50. Check(source, func, resultSelector);
  51. foreach (var item in source) {
  52. seed = func(seed, item);
  53. }
  54. return resultSelector(seed);
  55. }
  56. #endregion
  57. #region All
  58. public static bool All<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
  59. Check(source);
  60. foreach (T item in source) {
  61. if (!predicate(item)) {
  62. return false;
  63. }
  64. }
  65. return true;
  66. }
  67. #endregion
  68. #region Any
  69. public static bool Any<T>(this IEnumerable<T> source) {
  70. return source.Any(Funcs<T>.True);
  71. }
  72. public static bool Any<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
  73. Check(source, predicate);
  74. foreach (T item in source) {
  75. if (predicate(item)) {
  76. return true;
  77. }
  78. }
  79. return false;
  80. }
  81. #endregion
  82. #region Average
  83. public static double Average(this IEnumerable<int> source) {
  84. return Avg<int, long, double>(source, (a, v) => a + v, (a, c) => (double)a / (double)c);
  85. }
  86. public static double? Average(this IEnumerable<int?> source) {
  87. return AvgNullable<int, long, double>(source, (a, v) => a + v, (a, c) => (double)a / (double)c);
  88. }
  89. public static double Average(this IEnumerable<long> source) {
  90. return Avg<long, long, double>(source, (a, v) => a + v, (a, c) => (double)a / (double)c);
  91. }
  92. public static double? Average(this IEnumerable<long?> source) {
  93. return AvgNullable<long, long, double>(source, (a, v) => a + v, (a, c) => (double)a / (double)c);
  94. }
  95. public static float Average(this IEnumerable<float> source) {
  96. return Avg<float, float, float>(source, (a, v) => a + v, (a, c) => a / c);
  97. }
  98. public static float? Average(this IEnumerable<float?> source) {
  99. return AvgNullable<float, float, float>(source, (a, v) => a + v, (a, c) => a / c);
  100. }
  101. public static double Average(this IEnumerable<double> source) {
  102. return Avg<double, double, double>(source, (a, v) => a + v, (a, c) => a / c);
  103. }
  104. public static double? Average(this IEnumerable<double?> source) {
  105. return AvgNullable<double, double, double>(source, (a, v) => a + v, (a, c) => a / c);
  106. }
  107. public static Decimal Average(this IEnumerable<Decimal> source) {
  108. throw new NotImplementedException();
  109. }
  110. public static Decimal? Average(this IEnumerable<Decimal?> source) {
  111. throw new NotImplementedException();
  112. }
  113. public static double Average<T>(this IEnumerable<T> source, Func<T, int> selector) {
  114. return Avg<int, long, double>(source.Select(selector), (a, v) => a + v, (a, c) => (double)a / (double)c);
  115. }
  116. public static double? Average<T>(this IEnumerable<T> source, Func<T, int?> selector) {
  117. return AvgNullable<int, long, double>(source.Select(selector), (a, v) => a + v, (a, c) => (double)a / (double)c);
  118. }
  119. public static double Average<T>(this IEnumerable<T> source, Func<T, long> selector) {
  120. return Avg<long, long, double>(source.Select(selector), (a, v) => a + v, (a, c) => (double)a / (double)c);
  121. }
  122. public static double? Average<T>(this IEnumerable<T> source, Func<T, long?> selector) {
  123. return AvgNullable<long, long, double>(source.Select(selector), (a, v) => a + v, (a, c) => (double)a / (double)c);
  124. }
  125. public static float Average<T>(this IEnumerable<T> source, Func<T, float> selector) {
  126. return Avg<float, float, float>(source.Select(selector), (a, v) => a + v, (a, c) => a / c);
  127. }
  128. public static float? Average<T>(this IEnumerable<T> source, Func<T, float?> selector) {
  129. return AvgNullable<float, float, float>(source.Select(selector), (a, v) => a + v, (a, c) => a / c);
  130. }
  131. public static double Average<T>(this IEnumerable<T> source, Func<T, double> selector) {
  132. return Avg<double, double, double>(source.Select(selector), (a, v) => a + v, (a, c) => a / c);
  133. }
  134. public static double? Average<T>(this IEnumerable<T> source, Func<T, double?> selector) {
  135. return AvgNullable<double, double, double>(source.Select(selector), (a, v) => a + v, (a, c) => a / c);
  136. }
  137. public static Decimal Average<T>(this IEnumerable<T> source, Func<T, Decimal> selector) {
  138. throw new NotImplementedException();
  139. }
  140. public static Decimal? Average<T>(this IEnumerable<T> source, Func<T, Decimal?> selector) {
  141. throw new NotImplementedException();
  142. }
  143. private static TRes Avg<T, TAcc, TRes>(IEnumerable<T> source,
  144. Func<TAcc, T, TAcc> accFn, Func<TAcc, int, TRes> resFn) {
  145. Check(source);
  146. TAcc acc = default(TAcc);
  147. int counter = 0;
  148. foreach (var item in source) {
  149. acc = accFn(acc, item);
  150. counter++;
  151. }
  152. if (counter == 0) {
  153. throw new InvalidOperationException();
  154. }
  155. return resFn(acc, counter);
  156. }
  157. private static TRes? AvgNullable<T, TAcc, TRes>(IEnumerable<T?> source,
  158. Func<TAcc, T, TAcc> accFn, Func<TAcc, int, TRes> resFn)
  159. where T : struct
  160. where TRes : struct {
  161. Check(source);
  162. TAcc acc = default(TAcc);
  163. int counter = 0;
  164. foreach (var item in source) {
  165. if (item != null) {
  166. acc = accFn(acc, item.Value);
  167. counter++;
  168. }
  169. }
  170. if (counter == 0) {
  171. return null;
  172. }
  173. return resFn(acc, counter);
  174. }
  175. #endregion
  176. #region AsEnumerable
  177. public static IEnumerable<T> AsEnumerable<T>(this IEnumerable<T> source) {
  178. return source;
  179. }
  180. #endregion
  181. #region Cast
  182. public static IEnumerable<T> Cast<T>(IEnumerable source) {
  183. Check(source);
  184. return CastIterator<T>(source);
  185. }
  186. private static IEnumerable<T> CastIterator<T>(IEnumerable source) {
  187. foreach (T item in source) {
  188. yield return item;
  189. }
  190. }
  191. #endregion
  192. #region Concat
  193. public static IEnumerable<T> Concat<T>
  194. (this IEnumerable<T> first, IEnumerable<T> second) {
  195. Check(first, second);
  196. return ConcatIterator(first, second);
  197. }
  198. private static IEnumerable<T> ConcatIterator<T>
  199. (IEnumerable<T> first, IEnumerable<T> second) {
  200. foreach (T item in first) {
  201. yield return item;
  202. }
  203. foreach (T item in second) {
  204. yield return item;
  205. }
  206. }
  207. #endregion
  208. #region Contains
  209. public static bool Contains<T>(this IEnumerable<T> source, T value) {
  210. return source.Contains(value, null);
  211. }
  212. public static bool Contains<T>
  213. (this IEnumerable<T> source, T value, IEqualityComparer<T> comparer) {
  214. Check(source);
  215. if (comparer == null) {
  216. comparer = EqualityComparer<T>.Default;
  217. }
  218. foreach (T item in source) {
  219. if (comparer.Equals(item, value)) {
  220. return true;
  221. }
  222. }
  223. return false;
  224. }
  225. #endregion
  226. #region Count, LongCount
  227. public static int Count<T>(this IEnumerable<T> source) {
  228. Check(source);
  229. ICollection<T> collection = source as ICollection<T>;
  230. if (collection != null) {
  231. return collection.Count;
  232. } else {
  233. return source.Count(Funcs<T>.True);
  234. }
  235. }
  236. public static int Count<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
  237. Check(source, predicate);
  238. int count = 0;
  239. foreach (T item in source) {
  240. if (predicate(item)) {
  241. count++;
  242. }
  243. }
  244. return count;
  245. }
  246. public static long LongCount<T>(this IEnumerable<T> source) {
  247. return (long)Count(source);
  248. }
  249. public static long LongCount<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
  250. return (long)Count(source, predicate);
  251. }
  252. #endregion
  253. #region DefaultIfEmpty
  254. public static IEnumerable<T> DefaultIfEmpty<T>(this IEnumerable<T> source) {
  255. return source.DefaultIfEmpty(default(T));
  256. }
  257. public static IEnumerable<T> DefaultIfEmpty<T>(this IEnumerable<T> source, T defaultValue) {
  258. Check(source);
  259. return DefaultIfEmptyIterator(source, defaultValue);
  260. }
  261. private static IEnumerable<T> DefaultIfEmptyIterator<T>(IEnumerable<T> source, T defaultValue) {
  262. using (IEnumerator<T> en = source.GetEnumerator()) {
  263. if (en.MoveNext()) {
  264. do {
  265. yield return en.Current;
  266. } while (en.MoveNext());
  267. } else {
  268. yield return defaultValue;
  269. }
  270. }
  271. }
  272. #endregion
  273. #region Distinct
  274. public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source) {
  275. return Distinct(source, null);
  276. }
  277. public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source, IEqualityComparer<T> comparer) {
  278. return DistinctIterator(source, comparer);
  279. }
  280. private static IEnumerable<T> DistinctIterator<T>(IEnumerable<T> source, IEqualityComparer<T> comparer) {
  281. HashSet<T> h = new HashSet<T>(comparer);
  282. foreach (T item in source) {
  283. if (h.Add(item)) {
  284. yield return item;
  285. }
  286. }
  287. }
  288. #endregion
  289. #region ElementAt, ElementAtOrDefault
  290. public static T ElementAt<T>(IEnumerable<T> source, int index) {
  291. return ElementAt(source, index, false);
  292. }
  293. public static T ElementAtOrDefault<T>(IEnumerable<T> source, int index) {
  294. return ElementAt(source, index, true);
  295. }
  296. private static T ElementAt<T>(IEnumerable<T> source, int index, bool orDefault) {
  297. Check(source);
  298. if (index >= 0) {
  299. IList<T> list = source as IList<T>;
  300. if (list != null) {
  301. if (index < list.Count) {
  302. return list[index];
  303. }
  304. } else {
  305. int count = 0;
  306. foreach (T item in source) {
  307. if (count == index) {
  308. return item;
  309. }
  310. count++;
  311. }
  312. }
  313. }
  314. if (orDefault) {
  315. return default(T);
  316. } else {
  317. throw new ArgumentOutOfRangeException();
  318. }
  319. }
  320. #endregion
  321. #region Empty
  322. public static IEnumerable<T> Empty<T>() {
  323. return new T[0];
  324. }
  325. #endregion
  326. #region Except
  327. public static IEnumerable<T> Except<T>(this IEnumerable<T> first, IEnumerable<T> second) {
  328. return Except(first, second, null);
  329. }
  330. public static IEnumerable<T> Except<T>
  331. (this IEnumerable<T> first, IEnumerable<T> second, IEqualityComparer<T> comparer) {
  332. Check(first, second);
  333. return ExceptIterator(first, second, comparer);
  334. }
  335. private static IEnumerable<T> ExceptIterator<T>
  336. (IEnumerable<T> first, IEnumerable<T> second, IEqualityComparer<T> comparer) {
  337. HashSet<T> h = new HashSet<T>(second, comparer);
  338. foreach (T item in first) {
  339. if (!h.Contains(item)) {
  340. yield return item;
  341. }
  342. }
  343. }
  344. #endregion
  345. #region First, FirstOrDefault, Single, SingleOrDefault
  346. private static T FirstSingle<T>(IEnumerable<T> source, Func<T, bool> predicate, bool single, bool retDefault) {
  347. Check(source, predicate);
  348. using (var en = source.Where(predicate).GetEnumerator()) {
  349. if (en.MoveNext()) {
  350. T value = en.Current;
  351. if (single) {
  352. if (en.MoveNext()) {
  353. throw new InvalidOperationException();
  354. }
  355. }
  356. return value;
  357. } else {
  358. if (retDefault) {
  359. return default(T);
  360. } else {
  361. throw new InvalidOperationException();
  362. }
  363. }
  364. }
  365. }
  366. public static T First<T>(this IEnumerable<T> source) {
  367. return FirstSingle(source, Funcs<T>.True, false, false);
  368. }
  369. public static T First<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
  370. return FirstSingle(source, predicate, false, false);
  371. }
  372. public static T FirstOrDefault<T>(this IEnumerable<T> source) {
  373. return FirstSingle(source, Funcs<T>.True, false, true);
  374. }
  375. public static T FirstOrDefault<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
  376. return FirstSingle(source, predicate, false, true);
  377. }
  378. public static T Single<T>(this IEnumerable<T> source) {
  379. return FirstSingle(source, Funcs<T>.True, true, false);
  380. }
  381. public static T Single<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
  382. return FirstSingle(source, predicate, true, false);
  383. }
  384. public static T SingleOrDefault<T>(this IEnumerable<T> source) {
  385. return FirstSingle(source, Funcs<T>.True, true, true);
  386. }
  387. public static T SingleOrDefault<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
  388. return FirstSingle(source, predicate, true, true);
  389. }
  390. #endregion
  391. #region GroupBy
  392. public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>
  393. (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) {
  394. return source.GroupBy(keySelector, null);
  395. }
  396. public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>
  397. (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  398. IEqualityComparer<TKey> comparer) {
  399. return source.GroupBy(keySelector, Funcs<TSource>.Identity, comparer);
  400. }
  401. public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>
  402. (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  403. Func<TSource, TElement> elementSelector) {
  404. return source.GroupBy(keySelector, elementSelector, null);
  405. }
  406. public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>
  407. (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  408. Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer) {
  409. return source.GroupBy(keySelector, elementSelector,
  410. (key, elements) => (IGrouping<TKey, TElement>)new Grouping<TKey, TElement>(key, elements),
  411. comparer);
  412. }
  413. public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>
  414. (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  415. Func<TKey, IEnumerable<TSource>, TResult> resultSelector) {
  416. return source.GroupBy(keySelector, resultSelector, null);
  417. }
  418. public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>
  419. (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  420. Func<TKey, IEnumerable<TSource>, TResult> resultSelector, IEqualityComparer<TKey> comparer) {
  421. return source.GroupBy(keySelector, Funcs<TSource>.Identity, resultSelector, comparer);
  422. }
  423. public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>
  424. (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  425. Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector) {
  426. return source.GroupBy(keySelector, elementSelector, resultSelector, null);
  427. }
  428. public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>
  429. (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  430. Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector,
  431. IEqualityComparer<TKey> comparer) {
  432. Check(source, keySelector, elementSelector);
  433. Check(resultSelector);
  434. return GroupByIterator(source, keySelector, elementSelector, resultSelector, comparer);
  435. }
  436. private static IEnumerable<TResult> GroupByIterator<TSource, TKey, TElement, TResult>
  437. (IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  438. Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector,
  439. IEqualityComparer<TKey> comparer) {
  440. Dictionary<TKey, List<TElement>> groups = new Dictionary<TKey, List<TElement>>(comparer);
  441. foreach (var item in source) {
  442. TKey key = keySelector(item);
  443. TElement element = elementSelector(item);
  444. List<TElement> itemsInGroup;
  445. if (!groups.TryGetValue(key, out itemsInGroup)) {
  446. itemsInGroup = new List<TElement>();
  447. groups.Add(key, itemsInGroup);
  448. }
  449. itemsInGroup.Add(element);
  450. }
  451. foreach (var group in groups) {
  452. yield return resultSelector(group.Key, group.Value);
  453. }
  454. }
  455. #endregion
  456. #region GroupJoin
  457. public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>
  458. (this IEnumerable<TOuter> outer, IEnumerable<TInner> inner,
  459. Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector,
  460. Func<TOuter, IEnumerable<TInner>, TResult> resultSelector) {
  461. return outer.GroupJoin(inner, outerKeySelector, innerKeySelector, resultSelector, null);
  462. }
  463. public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>
  464. (this IEnumerable<TOuter> outer, IEnumerable<TInner> inner,
  465. Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector,
  466. Func<TOuter, IEnumerable<TInner>, TResult> resultSelector,
  467. IEqualityComparer<TKey> comparer) {
  468. Check(outer, inner, outerKeySelector);
  469. Check(innerKeySelector, resultSelector);
  470. return GroupJoinIterator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
  471. }
  472. public static IEnumerable<TResult> GroupJoinIterator<TOuter, TInner, TKey, TResult>
  473. (IEnumerable<TOuter> outer, IEnumerable<TInner> inner,
  474. Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector,
  475. Func<TOuter, IEnumerable<TInner>, TResult> resultSelector,
  476. IEqualityComparer<TKey> comparer) {
  477. var innerLookup = inner.ToLookup(innerKeySelector, comparer);
  478. foreach (var outerItem in outer) {
  479. TKey outerKey = outerKeySelector(outerItem);
  480. yield return resultSelector(outerItem,
  481. innerLookup.Contains(outerKey) ? innerLookup[outerKey] : Empty<TInner>());
  482. }
  483. }
  484. #endregion
  485. #region Intersect
  486. public static IEnumerable<T> Intersect<T>(this IEnumerable<T> first, IEnumerable<T> second) {
  487. return first.Intersect(second, null);
  488. }
  489. public static IEnumerable<T> Intersect<T>(this IEnumerable<T> first, IEnumerable<T> second,
  490. IEqualityComparer<T> comparer) {
  491. Check(first, second);
  492. return IntersectIterator(first, second, comparer);
  493. }
  494. private static IEnumerable<T> IntersectIterator<T>(IEnumerable<T> first, IEnumerable<T> second,
  495. IEqualityComparer<T> comparer) {
  496. HashSet<T> hash = new HashSet<T>(first, comparer);
  497. foreach (var item in second.Distinct(comparer)) {
  498. if (hash.Contains(item)) {
  499. yield return item;
  500. }
  501. }
  502. }
  503. #endregion
  504. #region Join
  505. public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>
  506. (this IEnumerable<TOuter> outer, IEnumerable<TInner> inner,
  507. Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector,
  508. Func<TOuter, TInner, TResult> resultSelector) {
  509. return outer.Join(inner, outerKeySelector, innerKeySelector, resultSelector, null);
  510. }
  511. public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>
  512. (this IEnumerable<TOuter> outer, IEnumerable<TInner> inner,
  513. Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector,
  514. Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer) {
  515. Check(outer, inner);
  516. Check(outerKeySelector, innerKeySelector, resultSelector);
  517. return JoinIterator(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
  518. }
  519. private static IEnumerable<TResult> JoinIterator<TOuter, TInner, TKey, TResult>
  520. (IEnumerable<TOuter> outer, IEnumerable<TInner> inner,
  521. Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector,
  522. Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer) {
  523. var outerLookup = outer.ToLookup(outerKeySelector, comparer);
  524. foreach (TInner innerItem in inner) {
  525. TKey innerKey = innerKeySelector(innerItem);
  526. if (outerLookup.Contains(innerKey)) {
  527. foreach (TOuter outerItem in outerLookup[innerKey]) {
  528. yield return resultSelector(outerItem, innerItem);
  529. }
  530. }
  531. }
  532. }
  533. #endregion
  534. #region Last, LastOrDefault
  535. private static T LastOrDefault<T>(IEnumerable<T> source, Func<T, bool> predicate, bool retDefault) {
  536. Check(source, predicate);
  537. T last = default(T);
  538. bool empty = true;
  539. foreach (T item in source) {
  540. if (predicate(item)) {
  541. empty = false;
  542. last = item;
  543. }
  544. }
  545. if (empty && !retDefault) {
  546. throw new InvalidOperationException();
  547. }
  548. return last;
  549. }
  550. public static T Last<T>(this IEnumerable<T> source) {
  551. return LastOrDefault(source, Funcs<T>.True, false);
  552. }
  553. public static T Last<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
  554. return LastOrDefault(source, predicate, false);
  555. }
  556. public static T LastOrDefault<T>(this IEnumerable<T> source) {
  557. return LastOrDefault(source, Funcs<T>.True, true);
  558. }
  559. public static T LastOrDefault<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
  560. return LastOrDefault(source, predicate, true);
  561. }
  562. #endregion
  563. #region Max
  564. public static int Max(this IEnumerable<int> source) {
  565. return GenProc(source, (a, b) => Math.Max(a, b), false);
  566. }
  567. public static int? Max(this IEnumerable<int?> source) {
  568. return GenProcNullable(source, (a, b) => Math.Max(a, b));
  569. }
  570. public static long Max(this IEnumerable<long> source) {
  571. return GenProc(source, (a, b) => Math.Max(a, b), false);
  572. }
  573. public static long? Max(this IEnumerable<long?> source) {
  574. return GenProcNullable(source, (a, b) => Math.Max(a, b));
  575. }
  576. public static float Max(this IEnumerable<float> source) {
  577. return GenProc(source, (a, b) => Math.Max(a, b), false);
  578. }
  579. public static float? Max(this IEnumerable<float?> source) {
  580. return GenProcNullable(source, (a, b) => Math.Max(a, b));
  581. }
  582. public static double Max(this IEnumerable<double> source) {
  583. return GenProc(source, (a, b) => Math.Max(a, b), false);
  584. }
  585. public static double? Max(this IEnumerable<double?> source) {
  586. return GenProcNullable(source, (a, b) => Math.Max(a, b));
  587. }
  588. public static Decimal Max(this IEnumerable<Decimal> source) {
  589. throw new NotImplementedException();
  590. }
  591. public static Decimal? Max(this IEnumerable<Decimal?> source) {
  592. throw new NotImplementedException();
  593. }
  594. public static T Max<T>(this IEnumerable<T> source) {
  595. Comparer<T> comparer = Comparer<T>.Default;
  596. return GenProc(source, (a, b) => comparer.Compare(a, b) > 0 ? a : b, true);
  597. }
  598. public static TResult Max<T, TResult>(this IEnumerable<T> source, Func<T, TResult> selector) {
  599. return Max(source.Select(selector));
  600. }
  601. public static int Max<T>(this IEnumerable<T> source, Func<T, int> selector) {
  602. return Max(source.Select(selector));
  603. }
  604. public static int? Max<T>(this IEnumerable<T> source, Func<T, int?> selector) {
  605. return Max(source.Select(selector));
  606. }
  607. public static long Max<T>(this IEnumerable<T> source, Func<T, long> selector) {
  608. return Max(source.Select(selector));
  609. }
  610. public static long? Max<T>(this IEnumerable<T> source, Func<T, long?> selector) {
  611. return Max(source.Select(selector));
  612. }
  613. public static float Max<T>(this IEnumerable<T> source, Func<T, float> selector) {
  614. return Max(source.Select(selector));
  615. }
  616. public static float? Max<T>(this IEnumerable<T> source, Func<T, float?> selector) {
  617. return Max(source.Select(selector));
  618. }
  619. public static double Max<T>(this IEnumerable<T> source, Func<T, double> selector) {
  620. return Max(source.Select(selector));
  621. }
  622. public static double? Max<T>(this IEnumerable<T> source, Func<T, double?> selector) {
  623. return Max(source.Select(selector));
  624. }
  625. public static Decimal Max<T>(this IEnumerable<T> source, Func<T, Decimal> selector) {
  626. return Max(source.Select(selector));
  627. }
  628. public static Decimal? Max<T>(this IEnumerable<T> source, Func<T, Decimal?> selector) {
  629. return Max(source.Select(selector));
  630. }
  631. #endregion
  632. #region Min
  633. public static int Min(this IEnumerable<int> source) {
  634. return GenProc(source, (a, b) => Math.Min(a, b), false);
  635. }
  636. public static int? Min(this IEnumerable<int?> source) {
  637. return GenProcNullable(source, (a, b) => Math.Min(a, b));
  638. }
  639. public static long Min(this IEnumerable<long> source) {
  640. return GenProc(source, (a, b) => Math.Min(a, b), false);
  641. }
  642. public static long? Min(this IEnumerable<long?> source) {
  643. return GenProcNullable(source, (a, b) => Math.Min(a, b));
  644. }
  645. public static float Min(this IEnumerable<float> source) {
  646. return GenProc(source, (a, b) => Math.Min(a, b), false);
  647. }
  648. public static float? Min(this IEnumerable<float?> source) {
  649. return GenProcNullable(source, (a, b) => Math.Min(a, b));
  650. }
  651. public static double Min(this IEnumerable<double> source) {
  652. return GenProc(source, (a, b) => Math.Min(a, b), false);
  653. }
  654. public static double? Min(this IEnumerable<double?> source) {
  655. return GenProcNullable(source, (a, b) => Math.Min(a, b));
  656. }
  657. public static Decimal Min(this IEnumerable<Decimal> source) {
  658. throw new NotImplementedException();
  659. }
  660. public static Decimal? Min(this IEnumerable<Decimal?> source) {
  661. throw new NotImplementedException();
  662. }
  663. public static T Min<T>(this IEnumerable<T> source) {
  664. Comparer<T> comparer = Comparer<T>.Default;
  665. return GenProc(source, (a, b) => comparer.Compare(a, b) < 0 ? a : b, true);
  666. }
  667. public static TResult Min<T, TResult>(this IEnumerable<T> source, Func<T, TResult> selector) {
  668. return Min(source.Select(selector));
  669. }
  670. public static int Min<T>(this IEnumerable<T> source, Func<T, int> selector) {
  671. return Min(source.Select(selector));
  672. }
  673. public static int? Min<T>(this IEnumerable<T> source, Func<T, int?> selector) {
  674. return Min(source.Select(selector));
  675. }
  676. public static long Min<T>(this IEnumerable<T> source, Func<T, long> selector) {
  677. return Min(source.Select(selector));
  678. }
  679. public static long? Min<T>(this IEnumerable<T> source, Func<T, long?> selector) {
  680. return Min(source.Select(selector));
  681. }
  682. public static float Min<T>(this IEnumerable<T> source, Func<T, float> selector) {
  683. return Min(source.Select(selector));
  684. }
  685. public static float? Min<T>(this IEnumerable<T> source, Func<T, float?> selector) {
  686. return Min(source.Select(selector));
  687. }
  688. public static double Min<T>(this IEnumerable<T> source, Func<T, double> selector) {
  689. return Min(source.Select(selector));
  690. }
  691. public static double? Min<T>(this IEnumerable<T> source, Func<T, double?> selector) {
  692. return Min(source.Select(selector));
  693. }
  694. public static Decimal Min<T>(this IEnumerable<T> source, Func<T, Decimal> selector) {
  695. return Min(source.Select(selector));
  696. }
  697. public static Decimal? Min<T>(this IEnumerable<T> source, Func<T, Decimal?> selector) {
  698. return Min(source.Select(selector));
  699. }
  700. private static T GenProc<T>(IEnumerable<T> source, Func<T, T, T> fn, bool allowEmpty) {
  701. Check(source);
  702. using (var en = source.GetEnumerator()) {
  703. if (!en.MoveNext()) {
  704. if (allowEmpty) {
  705. return default(T);
  706. } else {
  707. throw new InvalidOperationException();
  708. }
  709. }
  710. T value = en.Current;
  711. while (en.MoveNext()) {
  712. value = fn(value, en.Current);
  713. }
  714. return value;
  715. }
  716. }
  717. private static T? GenProcNullable<T>(IEnumerable<T?> source, Func<T, T, T> fn) where T : struct {
  718. T? value = null;
  719. foreach (T? item in source) {
  720. if (value == null) {
  721. value = item;
  722. } else if (item != null) {
  723. value = fn(value.Value, item.Value);
  724. }
  725. }
  726. return value;
  727. }
  728. #endregion
  729. #region OfType
  730. public static IEnumerable<T> OfType<T>(this IEnumerable source) {
  731. Check(source);
  732. return OfTypeIterator<T>(source);
  733. }
  734. private static IEnumerable<T> OfTypeIterator<T>(IEnumerable source) {
  735. foreach (object item in source) {
  736. if (item is T) {
  737. yield return (T)item;
  738. }
  739. }
  740. }
  741. #endregion
  742. #region OrderBy, OrderByDescending
  743. public static IOrderedEnumerable<T> OrderBy<T, TKey>(
  744. this IEnumerable<T> source,
  745. Func<T, TKey> selector,
  746. IComparer<TKey> comparer) {
  747. Check(source, selector);
  748. return new OrderedEnumerable<T, TKey>(source, selector, comparer, true);
  749. }
  750. public static IOrderedEnumerable<T> OrderBy<T, TKey>(
  751. this IEnumerable<T> source,
  752. Func<T, TKey> selector) {
  753. Check(source, selector);
  754. return new OrderedEnumerable<T, TKey>(source, selector, null, true);
  755. }
  756. public static IOrderedEnumerable<T> OrderByDescending<T, TKey>(
  757. this IEnumerable<T> source,
  758. Func<T, TKey> selector,
  759. IComparer<TKey> comparer) {
  760. Check(source, selector);
  761. return new OrderedEnumerable<T, TKey>(source, selector, comparer, false);
  762. }
  763. public static IOrderedEnumerable<T> OrderByDescending<T, TKey>(
  764. this IEnumerable<T> source,
  765. Func<T, TKey> selector) {
  766. Check(source, selector);
  767. return new OrderedEnumerable<T, TKey>(source, selector, null, false);
  768. }
  769. #endregion
  770. #region Range
  771. public static IEnumerable<int> Range(int start, int count) {
  772. if (count < 0) {
  773. throw new ArgumentOutOfRangeException("count");
  774. }
  775. return RangeIterator(start, count);
  776. }
  777. private static IEnumerable<int> RangeIterator(int start, int count) {
  778. int end = start + count;
  779. for (int i = start; i < end; i++) {
  780. yield return i;
  781. }
  782. }
  783. #endregion
  784. #region Repeat
  785. public static IEnumerable<TResult> Repeat<TResult>(TResult element, int count) {
  786. if (count < 0) {
  787. throw new ArgumentOutOfRangeException("count");
  788. }
  789. return RepeatIterator(element, count);
  790. }
  791. private static IEnumerable<TResult> RepeatIterator<TResult>(TResult element, int count) {
  792. for (int i = 0; i < count; i++) {
  793. yield return element;
  794. }
  795. }
  796. #endregion
  797. #region Reverse
  798. public static IEnumerable<T> Reverse<T>(this IEnumerable<T> source) {
  799. Check(source);
  800. IList<T> list = source as IList<T> ?? new List<T>(source);
  801. return ReverseIterator(list);
  802. }
  803. private static IEnumerable<T> ReverseIterator<T>(IList<T> source) {
  804. for (int i = source.Count - 1; i >= 0; i--) {
  805. yield return source[i];
  806. }
  807. }
  808. #endregion
  809. #region Select
  810. public static IEnumerable<TResult> Select<T, TResult>
  811. (this IEnumerable<T> source, Func<T, TResult> selector) {
  812. Check(source, selector);
  813. return SelectIterator(source, selector);
  814. }
  815. private static IEnumerable<TResult> SelectIterator<T, TResult>
  816. (IEnumerable<T> source, Func<T, TResult> selector) {
  817. foreach (T item in source) {
  818. yield return selector(item);
  819. }
  820. }
  821. public static IEnumerable<TResult> Select<T, TResult>
  822. (this IEnumerable<T> source, Func<T, int, TResult> selector) {
  823. Check(source, selector);
  824. return SelectIterator(source, selector);
  825. }
  826. private static IEnumerable<TResult> SelectIterator<T, TResult>
  827. (IEnumerable<T> source, Func<T, int, TResult> selector) {
  828. int count = 0;
  829. foreach (T item in source) {
  830. yield return selector(item, count);
  831. count++;
  832. }
  833. }
  834. #endregion
  835. #region SelectMany
  836. public static IEnumerable<TResult> SelectMany<TSource, TResult>
  837. (this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector) {
  838. return source.SelectMany((s, i) => selector(s));
  839. }
  840. public static IEnumerable<TResult> SelectMany<TSource, TResult>
  841. (this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TResult>> selector) {
  842. return source.SelectMany(selector, (s, c) => c);
  843. }
  844. public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>
  845. (this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector,
  846. Func<TSource, TCollection, TResult> resultSelector) {
  847. return source.SelectMany((s, i) => collectionSelector(s), resultSelector);
  848. }
  849. public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>
  850. (this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TCollection>> collectionSelector,
  851. Func<TSource, TCollection, TResult> resultSelector) {
  852. Check(source, collectionSelector, resultSelector);
  853. return SelectManyIterator(source, collectionSelector, resultSelector);
  854. }
  855. private static IEnumerable<TResult> SelectManyIterator<TSource, TCollection, TResult>
  856. (IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TCollection>> collectionSelector,
  857. Func<TSource, TCollection, TResult> resultSelector) {
  858. int count = 0;
  859. foreach (TSource item in source) {
  860. foreach (TCollection col in collectionSelector(item, count)) {
  861. yield return resultSelector(item, col);
  862. }
  863. count++;
  864. }
  865. }
  866. #endregion
  867. #region SequenceEqual
  868. public static bool SequenceEqual<T>(this IEnumerable<T> first, IEnumerable<T> second) {
  869. return first.SequenceEqual(second, null);
  870. }
  871. public static bool SequenceEqual<T>(this IEnumerable<T> first, IEnumerable<T> second, IEqualityComparer<T> comparer) {
  872. Check(first, second);
  873. if (comparer == null) {
  874. comparer = EqualityComparer<T>.Default;
  875. }
  876. using (IEnumerator<T> en1 = first.GetEnumerator(), en2 = second.GetEnumerator()) {
  877. while (en1.MoveNext()) {
  878. if (!en2.MoveNext()) {
  879. return false;
  880. }
  881. if (!comparer.Equals(en1.Current, en2.Current)) {
  882. return false;
  883. }
  884. }
  885. return !en2.MoveNext();
  886. }
  887. }
  888. #endregion
  889. #region Skip
  890. public static IEnumerable<T> Skip<T>(this IEnumerable<T> source, int count) {
  891. Check(source);
  892. return SkipIterator(source, count);
  893. }
  894. private static IEnumerable<T> SkipIterator<T>(IEnumerable<T> source, int count) {
  895. foreach (T item in source) {
  896. if (count <= 0) {
  897. yield return item;
  898. }
  899. count--;
  900. }
  901. }
  902. #endregion
  903. #region SkipWhile
  904. public static IEnumerable<T> SkipWhile<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
  905. Check(source, predicate);
  906. return SkipWhileIterator(source, predicate);
  907. }
  908. public static IEnumerable<T> SkipWhileIterator<T>(IEnumerable<T> source, Func<T, bool> predicate) {
  909. bool skip = true;
  910. foreach (T item in source) {
  911. if (skip) {
  912. if (!predicate(item)) {
  913. skip = false;
  914. yield return item;
  915. }
  916. } else {
  917. yield return item;
  918. }
  919. }
  920. }
  921. public static IEnumerable<T> SkipWhile<T>(this IEnumerable<T> source, Func<T, int, bool> predicate) {
  922. Check(source, predicate);
  923. return SkipWhileIterator(source, predicate);
  924. }
  925. public static IEnumerable<T> SkipWhileIterator<T>(IEnumerable<T> source, Func<T, int, bool> predicate) {
  926. bool skip = true;
  927. int count = 0;
  928. foreach (T item in source) {
  929. if (skip) {
  930. if (!predicate(item, count)) {
  931. skip = false;
  932. yield return item;
  933. }
  934. } else {
  935. yield return item;
  936. }
  937. count++;
  938. }
  939. }
  940. #endregion
  941. #region Take
  942. public static IEnumerable<T> Take<T>(this IEnumerable<T> source, int count) {
  943. Check(source);
  944. return TakeIterator(source, count);
  945. }
  946. private static IEnumerable<T> TakeIterator<T>(IEnumerable<T> source, int count) {
  947. if (count <= 0) {
  948. yield break;
  949. }
  950. foreach (T item in source) {
  951. yield return item;
  952. count--;
  953. if (count == 0) {
  954. yield break;
  955. }
  956. }
  957. }
  958. #endregion
  959. #region TakeWhile
  960. public static IEnumerable<T> TakeWhile<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
  961. Check(source, predicate);
  962. return TakeWhileIterator(source, predicate);
  963. }
  964. private static IEnumerable<T> TakeWhileIterator<T>(IEnumerable<T> source, Func<T, bool> predicate) {
  965. foreach (T item in source) {
  966. if (!predicate(item)) {
  967. yield break;
  968. }
  969. yield return item;
  970. }
  971. }
  972. public static IEnumerable<T> TakeWhile<T>(this IEnumerable<T> source, Func<T, int, bool> predicate) {
  973. Check(source, predicate);
  974. return TakeWhileIterator(source, predicate);
  975. }
  976. private static IEnumerable<T> TakeWhileIterator<T>(IEnumerable<T> source, Func<T, int, bool> predicate) {
  977. int count = 0;
  978. foreach (T item in source) {
  979. if (!predicate(item, count)) {
  980. yield break;
  981. }
  982. yield return item;
  983. count++;
  984. }
  985. }
  986. #endregion
  987. #region ThenBy, ThenByDescending
  988. //public static IOrderedEnumerable<T> ThenBy<T, TKey>(this IOrderedEnumerable<T> source,
  989. // Func<T, TKey> keySelector) {
  990. // return source.ThenBy(keySelector, null);
  991. //}
  992. //public static IOrderedEnumerable<T> ThenBy<T, TKey>(this IOrderedEnumerable<T> source,
  993. // Func<T, TKey> keySelector, IComparer<TKey> comparer) {
  994. // Check(source, keySelector);
  995. // return source.CreateOrderedEnumerable(keySelector, comparer, false);
  996. //}
  997. //public static IOrderedEnumerable<T> ThenByDescending<T, TKey>(this IOrderedEnumerable<T> source,
  998. // Func<T, TKey> keySelector) {
  999. // return source.ThenByDescending(keySelector, null);
  1000. //}
  1001. //public static IOrderedEnumerable<T> ThenByDescending<T, TKey>(this IOrderedEnumerable<T> source,
  1002. // Func<T, TKey> keySelector, IComparer<TKey> comparer) {
  1003. // Check(source, keySelector);
  1004. // return source.CreateOrderedEnumerable(keySelector, comparer, true);
  1005. //}
  1006. #endregion
  1007. #region Union
  1008. public static IEnumerable<T> Union<T>(this IEnumerable<T> first, IEnumerable<T> second) {
  1009. return Union(first, second, null);
  1010. }
  1011. public static IEnumerable<T> Union<T>
  1012. (this IEnumerable<T> first, IEnumerable<T> second, IEqualityComparer<T> comparer) {
  1013. // Check not needed, as Concat() will do it
  1014. return DistinctIterator(first.Concat(second), comparer);
  1015. }
  1016. #endregion
  1017. #region Where
  1018. public static IEnumerable<T> Where<T>
  1019. (this IEnumerable<T> source, Func<T, bool> predicate) {
  1020. Check(source, predicate);
  1021. return WhereIterator(source, predicate);
  1022. }
  1023. private static IEnumerable<T> WhereIterator<T>
  1024. (IEnumerable<T> source, Func<T, bool> predicate) {
  1025. foreach (T item in source) {
  1026. if (predicate(item)) {
  1027. yield return item;
  1028. }
  1029. }
  1030. }
  1031. public static IEnumerable<T> Where<T>
  1032. (this IEnumerable<T> source, Func<T, int, bool> predicate) {
  1033. Check(source, predicate);
  1034. return WhereIterator(source, predicate);
  1035. }
  1036. private static IEnumerable<T> WhereIterator<T>
  1037. (IEnumerable<T> source, Func<T, int, bool> predicate) {
  1038. int count = 0;
  1039. foreach (T item in source) {
  1040. if (predicate(item, count)) {
  1041. yield return item;
  1042. }
  1043. count++;
  1044. }
  1045. }
  1046. #endregion
  1047. #region ToList, ToArray, ToDictionary, ToLookup
  1048. public static List<T> ToList<T>(this IEnumerable<T> source) {
  1049. Check(source);
  1050. return new List<T>(source);
  1051. }
  1052. public static T[] ToArray<T>(this IEnumerable<T> source) {
  1053. Check(source);
  1054. ICollection<T> collection =
  1055. source as ICollection<T> ?? new List<T>(source);
  1056. T[] result = new T[collection.Count];
  1057. collection.CopyTo(result, 0);
  1058. return result;
  1059. }
  1060. public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
  1061. this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) {
  1062. return source.ToDictionary(keySelector, Funcs<TSource>.Identity, null);
  1063. }
  1064. public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
  1065. this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  1066. IEqualityComparer<TKey> comparer) {
  1067. return source.ToDictionary(keySelector, Funcs<TSource>.Identity, comparer);
  1068. }
  1069. public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
  1070. this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  1071. Func<TSource, TElement> elementSelector) {
  1072. return source.ToDictionary(keySelector, elementSelector, null);
  1073. }
  1074. public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
  1075. this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  1076. Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer) {
  1077. Check(source, keySelector, elementSelector);
  1078. Dictionary<TKey, TElement> dict = new Dictionary<TKey, TElement>(comparer);
  1079. foreach (TSource item in source) {
  1080. dict.Add(keySelector(item), elementSelector(item));
  1081. }
  1082. return dict;
  1083. }
  1084. public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(
  1085. this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) {
  1086. return source.ToLookup(keySelector, Funcs<TSource>.Identity, null);
  1087. }
  1088. public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(
  1089. this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  1090. IEqualityComparer<TKey> comparer) {
  1091. return source.ToLookup(keySelector, Funcs<TSource>.Identity, comparer);
  1092. }
  1093. public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(
  1094. this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  1095. Func<TSource, TElement> elementSelector) {
  1096. return source.ToLookup(keySelector, elementSelector, null);
  1097. }
  1098. public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(
  1099. this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
  1100. Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer) {
  1101. Check(source, keySelector, elementSelector);
  1102. var lookup = new Dictionary<TKey, List<TElement>>(comparer);
  1103. foreach (TSource item in source) {
  1104. TKey key = keySelector(item);
  1105. if (key == null) {
  1106. throw new ArgumentNullException();
  1107. }
  1108. List<TElement> list;
  1109. if (!lookup.TryGetValue(key, out list)) {
  1110. list = new List<TElement>();
  1111. lookup.Add(key, list);
  1112. }
  1113. list.Add(elementSelector(item));
  1114. }
  1115. return new Lookup<TKey, TElement>(lookup);
  1116. }
  1117. #endregion
  1118. #region Checks
  1119. private static void Check(object o) {
  1120. if (o == null) {
  1121. throw new ArgumentNullException();
  1122. }
  1123. }
  1124. private static void Check(object o1, object o2) {
  1125. if (o1 == null || o2 == null) {
  1126. throw new ArgumentNullException();
  1127. }
  1128. }
  1129. private static void Check(object o1, object o2, object o3) {
  1130. if (o1 == null || o2 == null || o3 == null) {
  1131. throw new ArgumentNullException();
  1132. }
  1133. }
  1134. #endregion
  1135. }
  1136. }