Skip to content

Instantly share code, notes, and snippets.

@popcatalin81
Created October 15, 2020 17:02
Show Gist options
  • Save popcatalin81/02a0da921d6752f97a3239f1d6dde2a3 to your computer and use it in GitHub Desktop.
Save popcatalin81/02a0da921d6752f97a3239f1d6dde2a3 to your computer and use it in GitHub Desktop.
My Linqpad ultils
/// <summary>
/// Extensions class with enumerable extensions targeted at code generation
/// </summary>
public static class EnumerableExtensions
{
/// <summary>
/// Yields a single value
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
/// <returns></returns>
public static IEnumerable<T> Yield<T>(T instance)
{
yield return instance;
}
/// <summary>
/// Yields two values
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance1"></param>
/// <param name="instance2"></param>
/// <returns></returns>
public static IEnumerable<T> Yield<T>(T instance1, T instance2)
{
yield return instance1;
yield return instance2;
}
/// <summary>
/// Yields tree values
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance1"></param>
/// <param name="instance2"></param>
/// <param name="instance3"></param>
/// <returns></returns>
public static IEnumerable<T> Yield<T>(T instance1, T instance2, T instance3)
{
yield return instance1;
yield return instance2;
yield return instance3;
}
/// <summary>
/// Batches the source enumerable into a sequence of enumerable each containing <para>size</para> elements at most
/// </summary>
/// <typeparam name="T">Element Type</typeparam>
/// <param name="source">The source <see cref="IEnumerable{T}"/></param>
/// <param name="size">Size of the batch indicating the maximum number of elements in each batch sequence</param>
/// <returns></returns>
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int size)
{
if (size < 1) throw new ArgumentOutOfRangeException(nameof(size));
var enumerator = source.GetEnumerator();
IEnumerable<T> BatchCounter(int curentCount)
{
do
{
yield return enumerator.Current;
} while (--curentCount > 0 && enumerator.MoveNext());
}
while (enumerator.MoveNext())
{
yield return BatchCounter(size);
}
}
/// <summary>
/// Returns a wrapped enumerable that contains info for each enumerated item,
/// like the index in original source, and whether it's first or last element in the original source
/// </summary>
/// <typeparam name="T">the type of elements in sequence</typeparam>
/// <param name="source">the source</param>
/// <returns>wrapped enumerable sequence</returns>
public static IEnumerable<ItemInfo<T>> WithInfo<T>(this IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
IEnumerable<ItemInfo<T>> WithInfoIterator()
{
using (var enumerator = source.GetEnumerator())
{
int index = 0;
if (!enumerator.MoveNext())
yield break;
T current = enumerator.Current;
if (enumerator.MoveNext())
{
yield return new ItemInfo<T>(true, false, index++, current);
current = enumerator.Current;
}
else
{
yield return new ItemInfo<T>(true, true, index, current);
yield break;
}
while (enumerator.MoveNext())
{
var next = enumerator.Current;
yield return new ItemInfo<T>(false, false, index++, current);
current = next;
}
yield return new ItemInfo<T>(false, true, index, current);
}
}
return WithInfoIterator();
}
/// <summary>
/// Recreates the info for an enumerable sequence
/// </summary>
/// <typeparam name="T">the type of elements in sequence</typeparam>
/// <param name="source">the source</param>
/// <returns>wrapped enumerable sequence</returns>
public static IEnumerable<ItemInfo<T>> WithInfo<T>(this IEnumerable<ItemInfo<T>> source)
{
return WithInfo(source.Select(s => s.Item));
}
/// <summary>
/// Memoizes the enumerable
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></
public static IEnumerable<T> Memoize<T>(this IEnumerable<T> source)
{
if (source == null) throw new ArgumentNullException(nameof(source));
List<T> cache = new List<T>();
bool cacheComplete = false;
IEnumerable<T> Cached()
{
if (cacheComplete)
{
foreach (var element in cache)
{
yield return element;
}
}
else
{
foreach (var element in source)
{
cache.Add(element);
yield return element;
}
cacheComplete = true;
}
}
return Cached();
}
}
public struct ItemInfo<T>
{
[Flags]
private enum Info
{
None = 0,
IsFirst,
IsLast
}
internal ItemInfo(bool first, bool last, int index, T item)
{
info = (first ? Info.IsFirst : 0) | (last ? Info.IsLast : 0);
Index = index;
Item = item;
}
private readonly Info info;
public bool IsFirst => info.HasFlag(Info.IsFirst);
public bool IsLast => info.HasFlag(Info.IsLast);
public readonly int Index;
public readonly T Item;
}
/// <summary>
/// Extensions class with Array extensions targeted at working with tuples and deconstruction
/// </summary>
public static class ArrayExtensions
{
public static void Deconstruct<T>(this IList<T> list, out T first)
{
first = Ge(list, 0);
}
public static void Deconstruct<T>(this IList<T> list, out T first, out T second)
{
first = Ge(list, 0);
second = Ge(list, 1);
}
public static void Deconstruct<T>(this IList<T> list, out T first, out T second, out T third)
{
first = Ge(list, 0);
second = Ge(list, 1);
third = Ge(list, 2);
}
public static void Deconstruct<T>(this IList<T> list, out T first, out T second, out T third, out T forth)
{
first = Ge(list, 0);
second = Ge(list, 1);
third = Ge(list, 2);
forth = Ge(list, 3);
}
public static void Deconstruct<T>(this IList<T> list, out T first, out T second, out T third, out T forth, out T fifth)
{
first = Ge(list, 0);
second = Ge(list, 1);
third = Ge(list, 2);
forth = Ge(list, 3);
fifth = Ge(list, 4);
}
public static void Deconstruct<T>(this IList<T> list, out T first, out T second, out T third, out T forth, out T fifth, out T sixth)
{
first = Ge(list, 0);
second = Ge(list, 1);
third = Ge(list, 2);
forth = Ge(list, 3);
fifth = Ge(list, 4);
sixth = Ge(list, 5);
}
public static void Deconstruct<T>(this IList<T> list, out T first, out T second, out T third, out T forth, out T fifth, out T sixth, out T seventh)
{
first = Ge(list, 0);
second = Ge(list, 1);
third = Ge(list, 2);
forth = Ge(list, 3);
fifth = Ge(list, 4);
sixth = Ge(list, 5);
seventh = Ge(list, 6);
}
public static void Deconstruct<T>(this IList<T> list, out T first, out T second, out T third, out T forth, out T fifth, out T sixth, out T seventh, out T eigth)
{
first = Ge(list, 0);
second = Ge(list, 1);
third = Ge(list, 2);
forth = Ge(list, 3);
fifth = Ge(list, 4);
sixth = Ge(list, 5);
seventh = Ge(list, 6);
eigth = Ge(list, 7);
}
private static T Ge<T>(IList<T> list, int index)
{
if (index < list.Count)
return list[index];
return default(T);
}
}
public static class StringBuilderExtensions
{
public static IndentedStringBuilder Indented(this StringBuilder sb, int identSize = 4, char identChar = ' ')
{
return new IndentedStringBuilder(sb, identSize, identChar);
}
}
public class IndentedStringBuilder
{
private readonly StringBuilder sb;
private int ident = 0;
private int identSize = 0;
private bool newLine = false;
private char identChar;
internal IndentedStringBuilder(StringBuilder sb, int identSize = 4, char identChar = ' ')
{
this.sb = sb;
this.identSize = identSize;
this.identChar = identChar;
}
/// <summary>
/// Write line to string builder with current indent
/// </summary>
public IndentedStringBuilder W(string line = "")
{
Write(line);
return this;
}
/// <summary>
/// Write line to string builder and increase ident
/// </summary>
public IndentedStringBuilder WI(string line = "")
{
Write(line);
ident++;
return this;
}
/// <summary>
/// Increase ident and write line to string builder
/// </summary>
public IndentedStringBuilder IW(string line = "")
{
ident++;
Write(line);
return this;
}
/// <summary>
/// Write line to string builder and decrease ident
/// </summary>
public IndentedStringBuilder WD(string line = "")
{
Write(line);
ident--;
return this;
}
/// <summary>
/// Decrease ident and write line to string builder
/// </summary>
public IndentedStringBuilder DW(string line = "")
{
ident--;
Write(line);
return this;
}
/// <summary>
/// Append to current line
/// </summary>
public IndentedStringBuilder Append(string value = "")
{
sb.Append(value);
return this;
}
/// <summary>
/// Append to current line
/// </summary>
public IndentedStringBuilder Each<T>(IEnumerable<T> values, Action<IndentedStringBuilder, ItemInfo<T>> action)
{
foreach (var value in values.WithInfo())
{
action(this, value);
}
return this;
}
/// <summary>
/// Chain another builder action to this instance
/// </summary>
public IndentedStringBuilder Do(Action<IndentedStringBuilder> action)
{
action(this);
return this;
}
/// <summary>
/// Chain another builder action to this instance
/// </summary>
public IndentedStringBuilder Do<T>(Action<IndentedStringBuilder, T> action, T item)
{
action(this, item);
return this;
}
private void Write(string line)
{
if (newLine)
sb.AppendLine();
else
newLine = true;
if (string.IsNullOrEmpty(line))
return;
sb.Append(identChar, ident * identSize);
sb.Append(line);
}
public override string ToString()
{
return sb.ToString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment