Skip to content

Instantly share code, notes, and snippets.

@Pzixel
Forked from holyqqwqqasd/linq_ext.cs
Created November 20, 2023 18:12
Show Gist options
  • Save Pzixel/246df4519121d99fb080f04d82d82200 to your computer and use it in GitHub Desktop.
Save Pzixel/246df4519121d99fb080f04d82d82200 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Extensions.Linq
{
public static class XEnumerable
{
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source) where T : class =>
source.Where(x => x is {})!;
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source) where T : struct =>
source.Where(x => x is {}).Select(x => x.GetValueOrDefault());
public static T? FirstOrNull<T>(this IEnumerable<T> source) where T : class =>
source.FirstOrDefault();
public static T? FirstOrNull<T>(this IEnumerable<T?> source) where T : struct =>
source.FirstOrDefault();
public static T? FirstOrNull<T>(this IEnumerable<T> source, object? _ = null) where T : struct =>
source.Cast<T?>().FirstOrDefault();
public static T? SingleOrNull<T>(this IEnumerable<T> source) where T : class =>
source.SingleOrDefault();
public static T? SingleOrNull<T>(this IEnumerable<T> source, object? _ = null) where T : struct =>
source.Cast<T?>().SingleOrDefault();
public static IEnumerable<TResult> SelectWithState<T, TResult, TState>(
this IEnumerable<T> source,
Func<T, TState, (TResult Result, TState NewState)> mapFunc,
TState initialState)
{
var state = initialState;
return source.Select(x =>
{
var (result, newState) = mapFunc(x, state);
state = newState;
return result;
});
}
public static TSource? MaxByOrNull<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> selector,
IComparer<TKey>? comparer = null) where TSource : class
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (selector == null) throw new ArgumentNullException(nameof(selector));
comparer ??= Comparer<TKey>.Default;
using (var sourceIterator = source.GetEnumerator())
{
if (!sourceIterator.MoveNext())
return default;
var max = sourceIterator.Current;
var maxKey = selector(max);
while (sourceIterator.MoveNext())
{
var candidate = sourceIterator.Current;
var candidateProjected = selector(candidate);
if (comparer.Compare(candidateProjected, maxKey) > 0)
{
max = candidate;
maxKey = candidateProjected;
}
}
return max;
}
}
public static TSource? MaxByOrNull<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> selector,
IComparer<TKey>? comparer = null,
object? _ = null) where TSource : struct
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (selector == null) throw new ArgumentNullException(nameof(selector));
comparer ??= Comparer<TKey>.Default;
using (var sourceIterator = source.GetEnumerator())
{
if (!sourceIterator.MoveNext())
return default;
var max = sourceIterator.Current;
var maxKey = selector(max);
while (sourceIterator.MoveNext())
{
var candidate = sourceIterator.Current;
var candidateProjected = selector(candidate);
if (comparer.Compare(candidateProjected, maxKey) > 0)
{
max = candidate;
maxKey = candidateProjected;
}
}
return max;
}
}
public static TSource? MinByOrNull<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> selector,
IComparer<TKey>? comparer = null) where TSource : class
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (selector == null) throw new ArgumentNullException(nameof(selector));
comparer ??= Comparer<TKey>.Default;
using var sourceIterator = source.GetEnumerator();
if (!sourceIterator.MoveNext())
return default;
var min = sourceIterator.Current;
var minKey = selector(min);
while (sourceIterator.MoveNext())
{
var candidate = sourceIterator.Current;
var candidateProjected = selector(candidate);
if (comparer.Compare(candidateProjected, minKey) < 0)
{
min = candidate;
minKey = candidateProjected;
}
}
return min;
}
public static TSource? MinByOrNull<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> selector,
IComparer<TKey>? comparer = null,
object? _ = null) where TSource : struct
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (selector == null) throw new ArgumentNullException(nameof(selector));
comparer ??= Comparer<TKey>.Default;
using var sourceIterator = source.GetEnumerator();
if (!sourceIterator.MoveNext())
return default;
var min = sourceIterator.Current;
var minKey = selector(min);
while (sourceIterator.MoveNext())
{
var candidate = sourceIterator.Current;
var candidateProjected = selector(candidate);
if (comparer.Compare(candidateProjected, minKey) < 0)
{
min = candidate;
minKey = candidateProjected;
}
}
return min;
}
public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> source, TSource element,
IEqualityComparer<TSource>? comparer = null)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (element is null) throw new ArgumentNullException(nameof(element));
comparer ??= EqualityComparer<TSource>.Default;
using (var sourceIterator = source.GetEnumerator())
{
while (sourceIterator.MoveNext())
{
var candidate = sourceIterator.Current;
if (comparer.Equals(candidate, element))
continue;
yield return candidate;
}
}
}
public static IEnumerable<T[]> SliceOn<T>(this IEnumerable<T> source, int batchCapacity)
{
if (source is null)
throw new ArgumentNullException(nameof(source));
return source.SliceOnInternal(batchCapacity);
}
private static IEnumerable<T[]> SliceOnInternal<T>(this IEnumerable<T> source, int batchCapacity)
{
var buffer = new List<T>(batchCapacity);
foreach (var item in source)
{
buffer.Add(item);
if (buffer.Count == batchCapacity)
{
yield return buffer.ToArray();
buffer.Clear();
}
}
if (buffer.Count > 0)
yield return buffer.ToArray();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment