/Ix/NET/System.Interactive/EnumerableEx.Single.cs

http://rx.codeplex.com · C# · 672 lines · 398 code · 90 blank · 184 comment · 118 complexity · 9aebdb41e187cf100eb7f1e9eba030ba MD5 · raw file

  1. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Threading;
  6. namespace System.Linq
  7. {
  8. public static partial class EnumerableEx
  9. {
  10. /// <summary>
  11. /// Hides the enumerable sequence object identity.
  12. /// </summary>
  13. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  14. /// <param name="source">Source sequence.</param>
  15. /// <returns>Enumerable sequence with the same behavior as the original, but hiding the source object identity.</returns>
  16. /// <remarks>AsEnumerable doesn't hide the object identity, and simply acts as a cast to the IEnumerable&lt;TSource&gt; interface.</remarks>
  17. public static IEnumerable<TSource> Hide<TSource>(this IEnumerable<TSource> source)
  18. {
  19. if (source == null)
  20. throw new ArgumentNullException("source");
  21. return source.Hide_();
  22. }
  23. private static IEnumerable<TSource> Hide_<TSource>(this IEnumerable<TSource> source)
  24. {
  25. foreach (var item in source)
  26. yield return item;
  27. }
  28. /// <summary>
  29. /// Enumerates the sequence and invokes the given action for each value in the sequence.
  30. /// </summary>
  31. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  32. /// <param name="source">Source sequence.</param>
  33. /// <param name="onNext">Action to invoke for each element.</param>
  34. public static void ForEach<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext)
  35. {
  36. if (source == null)
  37. throw new ArgumentNullException("source");
  38. if (onNext == null)
  39. throw new ArgumentNullException("onNext");
  40. foreach (var item in source)
  41. onNext(item);
  42. }
  43. /// <summary>
  44. /// Enumerates the sequence and invokes the given action for each value in the sequence.
  45. /// </summary>
  46. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  47. /// <param name="source">Source sequence.</param>
  48. /// <param name="onNext">Action to invoke for each element.</param>
  49. public static void ForEach<TSource>(this IEnumerable<TSource> source, Action<TSource, int> onNext)
  50. {
  51. if (source == null)
  52. throw new ArgumentNullException("source");
  53. if (onNext == null)
  54. throw new ArgumentNullException("onNext");
  55. var i = 0;
  56. foreach (var item in source)
  57. onNext(item, i++);
  58. }
  59. /// <summary>
  60. /// Lazily invokes an action for each value in the sequence.
  61. /// </summary>
  62. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  63. /// <param name="source">Source sequence.</param>
  64. /// <param name="onNext">Action to invoke for each element.</param>
  65. /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
  66. public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext)
  67. {
  68. if (source == null)
  69. throw new ArgumentNullException("source");
  70. if (onNext == null)
  71. throw new ArgumentNullException("onNext");
  72. return DoHelper(source, onNext, _ => { }, () => { });
  73. }
  74. /// <summary>
  75. /// Lazily invokes an action for each value in the sequence, and executes an action for successful termination.
  76. /// </summary>
  77. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  78. /// <param name="source">Source sequence.</param>
  79. /// <param name="onNext">Action to invoke for each element.</param>
  80. /// <param name="onCompleted">Action to invoke on successful termination of the sequence.</param>
  81. /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
  82. public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)
  83. {
  84. if (source == null)
  85. throw new ArgumentNullException("source");
  86. if (onNext == null)
  87. throw new ArgumentNullException("onNext");
  88. if (onCompleted == null)
  89. throw new ArgumentNullException("onCompleted");
  90. return DoHelper(source, onNext, _ => { }, onCompleted);
  91. }
  92. /// <summary>
  93. /// Lazily invokes an action for each value in the sequence, and executes an action upon exceptional termination.
  94. /// </summary>
  95. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  96. /// <param name="source">Source sequence.</param>
  97. /// <param name="onNext">Action to invoke for each element.</param>
  98. /// <param name="onError">Action to invoke on exceptional termination of the sequence.</param>
  99. /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
  100. public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
  101. {
  102. if (source == null)
  103. throw new ArgumentNullException("source");
  104. if (onNext == null)
  105. throw new ArgumentNullException("onNext");
  106. if (onError == null)
  107. throw new ArgumentNullException("onError");
  108. return DoHelper(source, onNext, onError, () => { });
  109. }
  110. /// <summary>
  111. /// Lazily invokes an action for each value in the sequence, and executes an action upon successful or exceptional termination.
  112. /// </summary>
  113. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  114. /// <param name="source">Source sequence.</param>
  115. /// <param name="onNext">Action to invoke for each element.</param>
  116. /// <param name="onError">Action to invoke on exceptional termination of the sequence.</param>
  117. /// <param name="onCompleted">Action to invoke on successful termination of the sequence.</param>
  118. /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
  119. public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
  120. {
  121. if (source == null)
  122. throw new ArgumentNullException("source");
  123. if (onNext == null)
  124. throw new ArgumentNullException("onNext");
  125. if (onError == null)
  126. throw new ArgumentNullException("onError");
  127. if (onCompleted == null)
  128. throw new ArgumentNullException("onCompleted");
  129. return DoHelper(source, onNext, onError, onCompleted);
  130. }
  131. #if !NO_RXINTERFACES
  132. /// <summary>
  133. /// Lazily invokes observer methods for each value in the sequence, and upon successful or exceptional termination.
  134. /// </summary>
  135. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  136. /// <param name="source">Source sequence.</param>
  137. /// <param name="observer">Observer to invoke notification calls on.</param>
  138. /// <returns>Sequence exhibiting the side-effects of observer method invocation upon enumeration.</returns>
  139. public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, IObserver<TSource> observer)
  140. {
  141. if (source == null)
  142. throw new ArgumentNullException("source");
  143. if (observer == null)
  144. throw new ArgumentNullException("observer");
  145. return DoHelper(source, observer.OnNext, observer.OnError, observer.OnCompleted);
  146. }
  147. #endif
  148. private static IEnumerable<TSource> DoHelper<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
  149. {
  150. using (var e = source.GetEnumerator())
  151. {
  152. while (true)
  153. {
  154. var current = default(TSource);
  155. try
  156. {
  157. if (!e.MoveNext())
  158. break;
  159. current = e.Current;
  160. }
  161. catch (Exception ex)
  162. {
  163. onError(ex);
  164. throw;
  165. }
  166. onNext(current);
  167. yield return current;
  168. }
  169. onCompleted();
  170. }
  171. }
  172. /// <summary>
  173. /// Generates a sequence of non-overlapping adjacent buffers over the source sequence.
  174. /// </summary>
  175. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  176. /// <param name="source">Source sequence.</param>
  177. /// <param name="count">Number of elements for allocated buffers.</param>
  178. /// <returns>Sequence of buffers containing source sequence elements.</returns>
  179. public static IEnumerable<IList<TSource>> Buffer<TSource>(this IEnumerable<TSource> source, int count)
  180. {
  181. if (source == null)
  182. throw new ArgumentNullException("source");
  183. if (count <= 0)
  184. throw new ArgumentOutOfRangeException("count");
  185. return source.Buffer_(count, count);
  186. }
  187. /// <summary>
  188. /// Generates a sequence of buffers over the source sequence, with specified length and possible overlap.
  189. /// </summary>
  190. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  191. /// <param name="source">Source sequence.</param>
  192. /// <param name="count">Number of elements for allocated buffers.</param>
  193. /// <param name="skip">Number of elements to skip between the start of consecutive buffers.</param>
  194. /// <returns>Sequence of buffers containing source sequence elements.</returns>
  195. public static IEnumerable<IList<TSource>> Buffer<TSource>(this IEnumerable<TSource> source, int count, int skip)
  196. {
  197. if (source == null)
  198. throw new ArgumentNullException("source");
  199. if (count <= 0)
  200. throw new ArgumentOutOfRangeException("count");
  201. if (skip <= 0)
  202. throw new ArgumentOutOfRangeException("skip");
  203. return source.Buffer_(count, skip);
  204. }
  205. private static IEnumerable<IList<TSource>> Buffer_<TSource>(this IEnumerable<TSource> source, int count, int skip)
  206. {
  207. var buffers = new Queue<IList<TSource>>();
  208. var i = 0;
  209. foreach (var item in source)
  210. {
  211. if (i % skip == 0)
  212. buffers.Enqueue(new List<TSource>(count));
  213. foreach (var buffer in buffers)
  214. buffer.Add(item);
  215. if (buffers.Count > 0 && buffers.Peek().Count == count)
  216. yield return buffers.Dequeue();
  217. i++;
  218. }
  219. while (buffers.Count > 0)
  220. yield return buffers.Dequeue();
  221. }
  222. /// <summary>
  223. /// Ignores all elements in the source sequence.
  224. /// </summary>
  225. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  226. /// <param name="source">Source sequence.</param>
  227. /// <returns>Source sequence without its elements.</returns>
  228. public static IEnumerable<TSource> IgnoreElements<TSource>(this IEnumerable<TSource> source)
  229. {
  230. if (source == null)
  231. throw new ArgumentNullException("source");
  232. return source.IgnoreElements_();
  233. }
  234. private static IEnumerable<TSource> IgnoreElements_<TSource>(this IEnumerable<TSource> source)
  235. {
  236. foreach (var item in source)
  237. ;
  238. yield break;
  239. }
  240. /// <summary>
  241. /// Returns elements with a distinct key value by using the default equality comparer to compare key values.
  242. /// </summary>
  243. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  244. /// <typeparam name="TKey">Key type.</typeparam>
  245. /// <param name="source">Source sequence.</param>
  246. /// <param name="keySelector">Key selector.</param>
  247. /// <returns>Sequence that contains the elements from the source sequence with distinct key values.</returns>
  248. public static IEnumerable<TSource> Distinct<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  249. {
  250. if (source == null)
  251. throw new ArgumentNullException("source");
  252. if (keySelector == null)
  253. throw new ArgumentNullException("keySelector");
  254. return source.Distinct_(keySelector, EqualityComparer<TKey>.Default);
  255. }
  256. /// <summary>
  257. /// Returns elements with a distinct key value by using the specified equality comparer to compare key values.
  258. /// </summary>
  259. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  260. /// <typeparam name="TKey">Key type.</typeparam>
  261. /// <param name="source">Source sequence.</param>
  262. /// <param name="keySelector">Key selector.</param>
  263. /// <param name="comparer">Comparer used to compare key values.</param>
  264. /// <returns>Sequence that contains the elements from the source sequence with distinct key values.</returns>
  265. public static IEnumerable<TSource> Distinct<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  266. {
  267. if (source == null)
  268. throw new ArgumentNullException("source");
  269. if (keySelector == null)
  270. throw new ArgumentNullException("keySelector");
  271. if (comparer == null)
  272. throw new ArgumentNullException("comparer");
  273. return source.Distinct_(keySelector, comparer);
  274. }
  275. private static IEnumerable<TSource> Distinct_<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  276. {
  277. var set = new HashSet<TKey>(comparer);
  278. foreach (var item in source)
  279. {
  280. var key = keySelector(item);
  281. if (set.Add(key))
  282. yield return item;
  283. }
  284. }
  285. #if NO_HASHSET
  286. class HashSet<T>
  287. {
  288. private Dictionary<T, object> _set;
  289. public HashSet(IEqualityComparer<T> comparer)
  290. {
  291. _set = new Dictionary<T, object>(comparer);
  292. }
  293. public bool Add(T value)
  294. {
  295. if (_set.ContainsKey(value))
  296. return false;
  297. _set[value] = null;
  298. return true;
  299. }
  300. }
  301. #endif
  302. /// <summary>
  303. /// Returns consecutive distinct elements by using the default equality comparer to compare values.
  304. /// </summary>
  305. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  306. /// <param name="source">Source sequence.</param>
  307. /// <returns>Sequence without adjacent non-distinct elements.</returns>
  308. public static IEnumerable<TSource> DistinctUntilChanged<TSource>(this IEnumerable<TSource> source)
  309. {
  310. if (source == null)
  311. throw new ArgumentNullException("source");
  312. return source.DistinctUntilChanged_(x => x, EqualityComparer<TSource>.Default);
  313. }
  314. /// <summary>
  315. /// Returns consecutive distinct elements by using the specified equality comparer to compare values.
  316. /// </summary>
  317. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  318. /// <param name="source">Source sequence.</param>
  319. /// <param name="comparer">Comparer used to compare values.</param>
  320. /// <returns>Sequence without adjacent non-distinct elements.</returns>
  321. public static IEnumerable<TSource> DistinctUntilChanged<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
  322. {
  323. if (source == null)
  324. throw new ArgumentNullException("source");
  325. if (comparer == null)
  326. throw new ArgumentNullException("comparer");
  327. return source.DistinctUntilChanged_(x => x, comparer);
  328. }
  329. /// <summary>
  330. /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values.
  331. /// </summary>
  332. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  333. /// <typeparam name="TKey">Key type.</typeparam>
  334. /// <param name="source">Source sequence.</param>
  335. /// <param name="keySelector">Key selector.</param>
  336. /// <returns>Sequence without adjacent non-distinct elements.</returns>
  337. public static IEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  338. {
  339. if (source == null)
  340. throw new ArgumentNullException("source");
  341. if (keySelector == null)
  342. throw new ArgumentNullException("keySelector");
  343. return source.DistinctUntilChanged_(keySelector, EqualityComparer<TKey>.Default);
  344. }
  345. /// <summary>
  346. /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values.
  347. /// </summary>
  348. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  349. /// <typeparam name="TKey">Key type.</typeparam>
  350. /// <param name="source">Source sequence.</param>
  351. /// <param name="keySelector">Key selector.</param>
  352. /// <param name="comparer">Comparer used to compare key values.</param>
  353. /// <returns>Sequence without adjacent non-distinct elements.</returns>
  354. public static IEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  355. {
  356. if (source == null)
  357. throw new ArgumentNullException("source");
  358. if (keySelector == null)
  359. throw new ArgumentNullException("keySelector");
  360. if (comparer == null)
  361. throw new ArgumentNullException("comparer");
  362. return source.DistinctUntilChanged_(keySelector, comparer);
  363. }
  364. private static IEnumerable<TSource> DistinctUntilChanged_<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  365. {
  366. var currentKey = default(TKey);
  367. var hasCurrentKey = false;
  368. foreach (var item in source)
  369. {
  370. var key = keySelector(item);
  371. var comparerEquals = false;
  372. if (hasCurrentKey)
  373. {
  374. comparerEquals = comparer.Equals(currentKey, key);
  375. }
  376. if (!hasCurrentKey || !comparerEquals)
  377. {
  378. hasCurrentKey = true;
  379. currentKey = key;
  380. yield return item;
  381. }
  382. }
  383. }
  384. /// <summary>
  385. /// Expands the sequence by recursively applying a selector function.
  386. /// </summary>
  387. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  388. /// <param name="source">Source sequence.</param>
  389. /// <param name="selector">Selector function to retrieve the next sequence to expand.</param>
  390. /// <returns>Sequence with results from the recursive expansion of the source sequence.</returns>
  391. public static IEnumerable<TSource> Expand<TSource>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> selector)
  392. {
  393. if (source == null)
  394. throw new ArgumentNullException("source");
  395. if (selector == null)
  396. throw new ArgumentNullException("selector");
  397. return source.Expand_(selector);
  398. }
  399. private static IEnumerable<TSource> Expand_<TSource>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> selector)
  400. {
  401. var queue = new Queue<IEnumerable<TSource>>();
  402. queue.Enqueue(source);
  403. while (queue.Count > 0)
  404. {
  405. var src = queue.Dequeue();
  406. foreach (var item in src)
  407. {
  408. queue.Enqueue(selector(item));
  409. yield return item;
  410. }
  411. }
  412. }
  413. /// <summary>
  414. /// Returns the source sequence prefixed with the specified value.
  415. /// </summary>
  416. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  417. /// <param name="source">Source sequence.</param>
  418. /// <param name="values">Values to prefix the sequence with.</param>
  419. /// <returns>Sequence starting with the specified prefix value, followed by the source sequence.</returns>
  420. public static IEnumerable<TSource> StartWith<TSource>(this IEnumerable<TSource> source, params TSource[] values)
  421. {
  422. if (source == null)
  423. throw new ArgumentNullException("source");
  424. return source.StartWith_(values);
  425. }
  426. private static IEnumerable<TSource> StartWith_<TSource>(this IEnumerable<TSource> source, params TSource[] values)
  427. {
  428. foreach (var x in values)
  429. yield return x;
  430. foreach (var item in source)
  431. yield return item;
  432. }
  433. /// <summary>
  434. /// Generates a sequence of accumulated values by scanning the source sequence and applying an accumulator function.
  435. /// </summary>
  436. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  437. /// <typeparam name="TAccumulate">Accumulation type.</typeparam>
  438. /// <param name="source">Source sequence.</param>
  439. /// <param name="seed">Accumulator seed value.</param>
  440. /// <param name="accumulator">Accumulation function to apply to the current accumulation value and each element of the sequence.</param>
  441. /// <returns>Sequence with all intermediate accumulation values resulting from scanning the sequence.</returns>
  442. public static IEnumerable<TAccumulate> Scan<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator)
  443. {
  444. if (source == null)
  445. throw new ArgumentNullException("source");
  446. if (accumulator == null)
  447. throw new ArgumentNullException("accumulator");
  448. return source.Scan_(seed, accumulator);
  449. }
  450. private static IEnumerable<TAccumulate> Scan_<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator)
  451. {
  452. var acc = seed;
  453. foreach (var item in source)
  454. {
  455. acc = accumulator(acc, item);
  456. yield return acc;
  457. }
  458. }
  459. /// <summary>
  460. /// Generates a sequence of accumulated values by scanning the source sequence and applying an accumulator function.
  461. /// </summary>
  462. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  463. /// <param name="source">Source sequence.</param>
  464. /// <param name="accumulator">Accumulation function to apply to the current accumulation value and each element of the sequence.</param>
  465. /// <returns>Sequence with all intermediate accumulation values resulting from scanning the sequence.</returns>
  466. public static IEnumerable<TSource> Scan<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> accumulator)
  467. {
  468. if (source == null)
  469. throw new ArgumentNullException("source");
  470. if (accumulator == null)
  471. throw new ArgumentNullException("accumulator");
  472. return source.Scan_(accumulator);
  473. }
  474. private static IEnumerable<TSource> Scan_<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> accumulator)
  475. {
  476. var hasSeed = false;
  477. var acc = default(TSource);
  478. foreach (var item in source)
  479. {
  480. if (!hasSeed)
  481. {
  482. hasSeed = true;
  483. acc = item;
  484. continue;
  485. }
  486. acc = accumulator(acc, item);
  487. yield return acc;
  488. }
  489. }
  490. /// <summary>
  491. /// Returns a specified number of contiguous elements from the end of the sequence.
  492. /// </summary>
  493. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  494. /// <param name="source">Source sequence.</param>
  495. /// <param name="count">The number of elements to take from the end of the sequence.</param>
  496. /// <returns>Sequence with the specified number of elements counting from the end of the source sequence.</returns>
  497. public static IEnumerable<TSource> TakeLast<TSource>(this IEnumerable<TSource> source, int count)
  498. {
  499. if (source == null)
  500. throw new ArgumentNullException("source");
  501. if (count < 0)
  502. throw new ArgumentOutOfRangeException("count");
  503. return source.TakeLast_(count);
  504. }
  505. private static IEnumerable<TSource> TakeLast_<TSource>(this IEnumerable<TSource> source, int count)
  506. {
  507. var q = new Queue<TSource>(count);
  508. foreach (var item in source)
  509. {
  510. if (q.Count >= count)
  511. q.Dequeue();
  512. q.Enqueue(item);
  513. }
  514. while (q.Count > 0)
  515. yield return q.Dequeue();
  516. }
  517. /// <summary>
  518. /// Bypasses a specified number of contiguous elements from the end of the sequence and returns the remaining elements.
  519. /// </summary>
  520. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  521. /// <param name="source">Source sequence.</param>
  522. /// <param name="count">The number of elements to skip from the end of the sequence before returning the remaining elements.</param>
  523. /// <returns>Sequence bypassing the specified number of elements counting from the end of the source sequence.</returns>
  524. public static IEnumerable<TSource> SkipLast<TSource>(this IEnumerable<TSource> source, int count)
  525. {
  526. if (source == null)
  527. throw new ArgumentNullException("source");
  528. if (count < 0)
  529. throw new ArgumentOutOfRangeException("count");
  530. return source.SkipLast_(count);
  531. }
  532. private static IEnumerable<TSource> SkipLast_<TSource>(this IEnumerable<TSource> source, int count)
  533. {
  534. var q = new Queue<TSource>();
  535. foreach (var x in source)
  536. {
  537. q.Enqueue(x);
  538. if (q.Count > count)
  539. yield return q.Dequeue();
  540. }
  541. }
  542. /// <summary>
  543. /// Repeats and concatenates the source sequence infinitely.
  544. /// </summary>
  545. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  546. /// <param name="source">Source sequence.</param>
  547. /// <returns>Sequence obtained by concatenating the source sequence to itself infinitely.</returns>
  548. public static IEnumerable<TSource> Repeat<TSource>(this IEnumerable<TSource> source)
  549. {
  550. if (source == null)
  551. throw new ArgumentNullException("source");
  552. return Repeat_(source);
  553. }
  554. private static IEnumerable<TSource> Repeat_<TSource>(IEnumerable<TSource> source)
  555. {
  556. while (true)
  557. foreach (var item in source)
  558. yield return item;
  559. }
  560. /// <summary>
  561. /// Repeats and concatenates the source sequence the given number of times.
  562. /// </summary>
  563. /// <typeparam name="TSource">Source sequence element type.</typeparam>
  564. /// <param name="source">Source sequence.</param>
  565. /// <param name="count">Number of times to repeat the source sequence.</param>
  566. /// <returns>Sequence obtained by concatenating the source sequence to itself the specified number of times.</returns>
  567. public static IEnumerable<TSource> Repeat<TSource>(this IEnumerable<TSource> source, int count)
  568. {
  569. if (source == null)
  570. throw new ArgumentNullException("source");
  571. if (count < 0)
  572. throw new ArgumentOutOfRangeException("count");
  573. return Repeat_(source, count);
  574. }
  575. private static IEnumerable<TSource> Repeat_<TSource>(IEnumerable<TSource> source, int count)
  576. {
  577. for (var i = 0; i < count; i++)
  578. foreach (var item in source)
  579. yield return item;
  580. }
  581. }
  582. }