Last active
November 27, 2017 14:01
-
-
Save shanecelis/39ae12fe8f3392716470b6cc6d1c1e68 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
/* | |
Some helpful Linq extensions I've used with Unity. | |
Original code from stackoverflow.com where user contributions are | |
licensed under CC-BY-SA 3.0 with attribution required. | |
*/ | |
public static class LinqExtensions { | |
// http://stackoverflow.com/questions/3645644/whats-your-favorite-linq-to-objects-operator-which-is-not-built-in | |
/// <summary>Creates a <see cref="Queue<T>"/> from an enumerable | |
/// collection.</summary> | |
public static Queue<T> ToQueue<T>(this IEnumerable<T> source) { | |
if (source == null) | |
throw new ArgumentNullException("source"); | |
return new Queue<T>(source); | |
} | |
/// <summary>Creates a <see cref="Stack<T>"/> from an enumerable | |
/// collection.</summary> | |
public static Stack<T> ToStack<T>(this IEnumerable<T> source) { | |
if (source == null) | |
throw new ArgumentNullException("source"); | |
return new Stack<T>(source); | |
} | |
public static bool IsEmpty<T>(this IEnumerable<T> source) { | |
return !source.Any(); | |
} | |
public static void Each<T>(this IEnumerable<T> items, Action<T> action) { | |
foreach (var i in items) | |
action(i); | |
} | |
/// <summary>Adds a single element to the end of an IEnumerable.</summary> | |
/// <typeparam name="T">Type of enumerable to return.</typeparam> | |
/// <returns>IEnumerable containing all the input elements, followed by the | |
/// specified additional element.</returns> | |
public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T element) { | |
if (source == null) | |
throw new ArgumentNullException("source"); | |
return concatIterator(element, source, false); | |
} | |
/// <summary>Adds a single element to the start of an IEnumerable.</summary> | |
/// <typeparam name="T">Type of enumerable to return.</typeparam> | |
/// <returns>IEnumerable containing the specified additional element, followed by | |
/// all the input elements.</returns> | |
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> tail, T head) { | |
if (tail == null) | |
throw new ArgumentNullException("tail"); | |
return concatIterator(head, tail, true); | |
} | |
private static IEnumerable<T> concatIterator<T>(T extraElement, | |
IEnumerable<T> source, | |
bool insertAtStart) { | |
if (insertAtStart) | |
yield return extraElement; | |
foreach (var e in source) | |
yield return e; | |
if (!insertAtStart) | |
yield return extraElement; | |
} | |
// http://stackoverflow.com/questions/10206557/c-sharp-cast-dictionarystring-anytype-to-dictionarystring-object-involvin | |
public static IEnumerable<DictionaryEntry> CastDict(this IEnumerable dictionary) { | |
foreach (DictionaryEntry entry in dictionary) | |
{ | |
yield return entry; | |
} | |
} | |
// https://code.msdn.microsoft.com/LINQ-to-DataSets-Custom-41738490 | |
public static IEnumerable<T2> Combine<T,T2>(this IEnumerable<T> first, | |
IEnumerable<T> second, | |
System.Func<T,T,T2> func) { | |
using (IEnumerator<T> e1 = first.GetEnumerator(), | |
e2 = second.GetEnumerator()) { | |
while (e1.MoveNext() && e2.MoveNext()) { | |
yield return func(e1.Current, e2.Current); | |
} | |
} | |
} | |
// http://stackoverflow.com/questions/3173718/how-to-get-a-random-object-using-linq | |
public static T Random<T>(this IEnumerable<T> enumerable) { | |
var r = new Random(); | |
var list = enumerable as IList<T> ?? enumerable.ToList(); | |
return list.ElementAt(r.Next(0, list.Count())); | |
} | |
// Reservoir Sampling | |
// https://en.wikipedia.org/wiki/Reservoir_sampling | |
/* | |
Return an IEnumerable with k random items from the given | |
enumerable with n items. | |
It's O(n) and doesn't need to get the count n first. | |
Note: The if the enumerable only has k items, the result will not | |
be shuffled. | |
*/ | |
public static IEnumerable<T> Random<T>(this IEnumerable<T> enumerable, | |
int k) { | |
var list = new List<T>(k); | |
using (var e = enumerable.GetEnumerator()) { | |
for (int i = 0; i < k && e.MoveNext(); i++) | |
list[i] = e.Current; | |
var r = new Random(); | |
int j; | |
for (int i = k + 1; e.MoveNext(); i++) { | |
j = r.Next(0, i); // [0, i) | |
if (j < k) | |
list[j] = e.Current; | |
} | |
return list; | |
} | |
} | |
/* | |
Behaves like .Skip(count) unless that would skip all the elements, in which | |
case it returns the last element. | |
new int[] {0, 1, 2, 3, 4}.Skip(10) -> { } | |
new int[] {0, 1, 2, 3, 4}.SkipUnlessLast(10) -> { 4 } | |
But otherwise behaves the same. | |
new int[] {0, 1, 2, 3, 4}.Skip(2) -> { 2, 3, 4 } | |
new int[] {0, 1, 2, 3, 4}.SkipUnlessLast(2) -> { 2, 3, 4 } | |
*/ | |
public static IEnumerable<T> SkipUnlessLast<T>(this IEnumerable<T> source, int count) { | |
// https://blogs.msmvps.com/jonskeet/2011/01/02/reimplementing-linq-to-objects-part-23-take-skip-takewhile-skipwhile/ | |
T lastItem = default(T); | |
using (IEnumerator<T> iterator = source.GetEnumerator()) { | |
for (int i = 0; i < count; i++) { | |
if (! iterator.MoveNext()) { | |
if (i != 0) | |
yield return lastItem; | |
yield break; | |
} else { | |
lastItem = iterator.Current; | |
} | |
} | |
bool anyMore = false; | |
while (iterator.MoveNext()) { | |
anyMore = true; | |
yield return iterator.Current; | |
} | |
if (! anyMore) | |
yield return lastItem; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment