Innovenergy_trunk/csharp/Lib/Utils/EnumerableUtils.cs

489 lines
12 KiB
C#

using System.Diagnostics.CodeAnalysis;
namespace InnovEnergy.Lib.Utils;
public static class EnumerableUtils
{
public static T? FirstOrNullableDefault<T>(this IEnumerable<T> ts, Func<T,Boolean> predicate) where T : struct
{
return ts
.Where(predicate)
.OfType<T?>()
.FirstOrDefault();
}
public static Int32 SequenceHash<T>(this IEnumerable<T> ts)
{
var hash = new HashCode();
hash.Add(typeof(T).GetHashCode());
foreach (var t in ts)
hash.Add(t?.GetHashCode());
return hash.ToHashCode();
}
public static IList<T> Push<T>(this IList<T> l, T t)
{
l.Add(t);
return l;
}
public static T Pop<T>(this IList<T> l)
{
var i = l.Count - 1;
var t = l[i];
l.RemoveAt(i);
return t;
}
// public static async Task<IEnumerable<R>> SelectManyAsync<T, R>(this IEnumerable<T> ts, Func<T, Task<IEnumerable<R>>> func)
// {
// var whenAll = await Task.WhenAll(ts.Select(func));
// return whenAll.SelectMany(s => s);
// }
// public static async Task<IEnumerable<R>> SelectManyAsync<T, R>(this IEnumerable<T> ts,
// Func<T, Task<IEnumerable<R>>> func)
// {
// var result = Enumerable.Empty<R>();
//
// foreach (var t in ts)
// {
// result = result.Concat(await func(t));
// }
//
// return result;
// }
// public static IEnumerable<Task<T>> SelectAsync<T>(this Task<IEnumerable<T>> ts)
// {
// yield return ts.ContinueWith(r => r.Result.First());
//
// foreach (var t in ts.Result.Skip(1))
// yield return Task.FromResult(t);
// }
public static Queue<T> ToQueue<T>(this IEnumerable<T> ts)
{
var q = new Queue<T>();
foreach (var t in ts)
q.Enqueue(t);
return q;
}
public static Stack<T> ToStack<T>(this IEnumerable<T> ts)
{
var s = new Stack<T>();
foreach (var t in ts)
s.Push(t);
return s;
}
public static async IAsyncEnumerable<R>
SelectManyAsync<T, R>(this IEnumerable<T> ts, Func<T, Task<IEnumerable<R>>> func)
{
foreach (var t in ts)
{
var rs = await func(t);
foreach (var r in rs)
yield return r;
}
}
public static IEnumerable<T> SelectTuple<L, R, T>(this IEnumerable<(L l, R r)> tuples, Func<L, R, T> map)
{
return tuples.Select(tuple => map(tuple.l, tuple.r));
}
public static Boolean AllEqual<T,R>(this IEnumerable<T> ts, Func<T,R> map)
{
return ts.Select(map).AllEqual();
}
public static Boolean AllEqual<T>(this IEnumerable<T> ts)
{
return !ts.Distinct().Skip(1).Any();
}
public static IReadOnlyList<T> NullableToReadOnlyList<T>(this T? t)
{
return t is null ? Array.Empty<T>() : new[] {t};
}
public static IEnumerable<T> NullableToEnumerable<T>(this T? t)
{
if (t is not null)
yield return t;
}
public static IEnumerable<(T left, T right)> Pairwise<T>(this IEnumerable<T> ts)
{
using var e = ts.GetEnumerator();
if (!e.MoveNext())
yield break;
var left = e.Current;
while (e.MoveNext())
{
yield return (left, e.Current);
left = e.Current;
}
}
public static IEnumerable<(T left, T right)> Pairwise<T>(this IEnumerable<T> ts, T seed)
{
using var e = ts.GetEnumerator();
var left = seed;
while (e.MoveNext())
{
yield return (left, e.Current);
left = e.Current;
}
}
public static IEnumerable<Int32> To(this Int32 start, Int32 end)
{
var d = Math.Sign(end - start);
for (var i = start; i != end; i+= d)
yield return i;
}
public static IEnumerable<UInt32> To(this UInt32 start, UInt32 end)
{
var d = Math.Sign(end - start).ConvertTo<UInt32>();
for (var i = start; i != end; i+= d)
yield return i;
}
public static IReadOnlyList<T> ToReadOnlyList<T>(this IEnumerable<T> src)
{
return src switch
{
T[] a => a,
List<T> l => l,
_ => src.ToList()
};
}
public static IReadOnlyList<T> ToReadOnlyList<T>(this IEnumerable<T> src, Int32 size) => ToArray(src, size);
public static List<T> ToList<T>(this IEnumerable<T> src, Int32 initialSize)
{
var list = new List<T>(initialSize);
list.AddRange(src);
return list;
}
public static IEnumerable<T> PadEnd<T>(this IEnumerable<T> src, Int32 length, T padding)
{
using var enumerator = src.GetEnumerator();
while (enumerator.MoveNext() && length-- > 0)
yield return enumerator.Current;
while (length-- > 0)
yield return padding;
}
public static IEnumerable<T> PadStart<T>(this IEnumerable<T> src, Int32 length, T padding)
{
return src
.Reverse()
.PadEnd(length, padding)
.Reverse();
}
public static IEnumerator<T> AsSingleEnumerator<T>(this T t)
{
yield return t;
}
public static IEnumerable<T> AsSingleEnumerable<T>(this T t)
{
yield return t;
}
public static IEnumerable<T> Flatten<T>(this IEnumerable<IEnumerable<T>> src) => src.SelectMany(s => s);
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach (var e in enumerable)
action(e);
return enumerable;
}
public static IEnumerable<T> Do<T>(this IEnumerable<T> enumerable, Action<T> action)
{
return enumerable.Select(e =>
{
action(e);
return e;
});
}
public static void ForEach<T,R>(this IEnumerable<T> enumerable, Func<T,R> func)
{
foreach (var e in enumerable)
func(e);
}
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T>? ts)
{
return ts ?? Enumerable.Empty<T>();
}
public static T ElementAtOr<T>(this IEnumerable<T> ts, Int32 index, T defaultValue)
{
return ts.ElementAtOrDefault(index) ?? defaultValue;
}
public static IEnumerable<T> Unfold<T>(this T seed, Func<T, T?> next)
{
var value = seed;
while (value is not null)
{
yield return value;
value = next(value);
}
}
public static IEnumerable<T> InfinitelyMany<T>(this T value)
{
while (true)
yield return value;
// ReSharper disable once IteratorNeverReturns
}
public static T[] ToArray<T>(this IEnumerable<T> ts, Int32 n)
{
var array = new T[n];
var i = 0;
using var enumerator = ts.GetEnumerator();
while (i < n && enumerator.MoveNext())
array[i++] = enumerator.Current;
if (enumerator.MoveNext())
throw new ArgumentOutOfRangeException(nameof(ts));
return array;
}
public static T[] ToArray<T>(this IReadOnlyList<T> ts)
{
return ts as T[] ?? ts.ToArray(ts.Count);
}
public static IEnumerable<T> Concat<T>(this IEnumerable<T> ts, T last)
{
foreach (var t in ts)
yield return t;
yield return last;
}
public static IEnumerable<T> Many<T>(this T value)
{
yield return value;
}
public static IEnumerable<T> PadWith<T>(this IEnumerable<T> enumerable, T padding)
{
return enumerable.Concat(padding.InfinitelyMany());
}
public static IEnumerable<T> PadWith<T>(this IEnumerable<T> enumerable, T padding, Int32 maxLength)
{
return enumerable
.PadWith(padding)
.Take(maxLength);
}
public static IEnumerable<T> Unless<T>(this IEnumerable<T> seq, Func<T, Boolean> filter)
{
return seq.Where(e => !filter(e));
}
public static IEnumerable<T> Intersperse<T>(this IEnumerable<T> enumerable, T interspersed)
{
using var e = enumerable.GetEnumerator();
if (! e.MoveNext()) yield break;
yield return e.Current;
while (e.MoveNext())
{
yield return interspersed;
yield return e.Current;
}
}
public static T Next<T>(this IEnumerator<T> enumerator)
{
enumerator.MoveNext();
return enumerator.Current;
}
public static IEnumerable<R> Scan<T, R>(this IEnumerable<T> src, R seed, Func<R, T, R> next)
{
var current = seed;
foreach (var t in src)
{
current = next(current, t);
yield return current;
}
}
[SuppressMessage("ReSharper", "AccessToDisposedClosure")]
public static IEnumerable<IEnumerable<T>> GroupUntil<T>(this IEnumerable<T> sequence, Func<T, T, Boolean> splitBetween)
{
using var e = sequence.GetEnumerator();
if(!e.MoveNext())
yield break; // empty sequence
var moreInSeq = false;
var moreInGroup = false;
do
{
yield return GetGroup();
while (moreInGroup)
MoveNext();
}
while (moreInSeq);
void MoveNext()
{
var prev = e.Current;
moreInSeq = e.MoveNext();
moreInGroup = moreInSeq && !splitBetween(prev, e.Current);
}
IEnumerable<T> GetGroup()
{
do
{
yield return e.Current;
MoveNext();
}
while (moreInGroup);
}
}
public static IEnumerable<T> NotNull<T>(this IEnumerable<T?> ts)
{
return ts.Where(t => t != null)!;
}
public static IEnumerable<Double> RandomWalk()
{
var rng = new Random();
var x = NextDx();
while (true)
{
yield return x;
x = (x + NextDx()) / 2;
}
Double NextDx() => rng.NextDouble() * 2 - 1;
}
public static IEnumerable<Double> Integrate(this IEnumerable<Double> source, Double initConst = 0)
{
return source.Scan(initConst, (x, y) => x + y);
}
public static IEnumerable<Double> IntegrateNormalize(this IEnumerable<Double> source, Double initConst = 0)
{
return source.Scan(initConst, (x, y) => Math.Tanh(x + y));
}
public static IEnumerable<Double> MovingAverage(this IEnumerable<Double> source, Int32 windowSize)
{
if (windowSize < 1)
throw new ArgumentException(nameof(windowSize) + " must be positive", nameof(windowSize));
using var e = source.GetEnumerator();
if (!e.MoveNext()) yield break;
var state = e.Current;
do
{
state = ((windowSize - 1) * state + e.Current) / windowSize;
yield return state;
}
while (e.MoveNext());
}
public static IEnumerable<T> ZeroOrOne<T>(this T? t)
{
if (t is not null)
yield return t;
}
public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> src)
{
return src
.SelectMany(line => line.Select((element, column) => (element, column)))
.GroupBy(i => i.column, i => i.element);
}
public static T GetNext<T>(this IReadOnlyList<T> ts, T current)
{
return ts
.Concat(ts)
.SkipWhile(t => !t!.Equals(current))
.Skip(1)
.First();
}
public static T GetPrevious<T>(this IReadOnlyList<T> ts, T current)
{
return GetNext(ts.Reverse().ToArray(ts.Count), current);
}
}