public static class LinqHelper { public static IEnumerable<T> Select<T>(params T[] args) => args; public static IEnumerable<T> SelectMany<T>(params IEnumerable<T>[] args) => args.SelectMany(x => x); public static List<T> List<T>(params T[] args) => args.ToList(); public static IEnumerable<IEnumerable<T>> Split<T>(IEnumerable<T> src, int size) => src.Where((x, i) => i % size == 0).Select((x, i) => src.Skip(i * size).Take(size)); public static bool HasSharedItem<T>(IEnumerable<T> left, IEnumerable<T> right) => left.Any(l => right.Any(r => l != null && r != null && l.Equals(r))); public static T GetValueIfExactOne<T>(IEnumerable<T> values, T defValue = default) { var distinct = values.Distinct(); return distinct.Count() == 1 ? distinct.First() : defValue; } public static async Task<IEnumerable<T>> FromAsync<T>(IAsyncEnumerable<T> items) { var list = new List<T>(); await foreach (var item in items) { list.Add(item); } return list; } public static async Task<IEnumerable<U>> FromAsync<T, U>(IAsyncEnumerable<T> items, Func<T, U> converter) { var list = new List<U>(); await foreach (var item in items) { list.Add(converter(item)); } return list; } public static T MinOrDefault<T>(this IEnumerable<T> sequence, T defValue = default(T)) => sequence.Any() ? sequence.Min() : defValue; public static T MaxOrDefault<T>(this IEnumerable<T> sequence, T defValue = default(T)) => sequence.Any() ? sequence.Max() : defValue; public static IEnumerable<(T item, int index)> WithIndex<T>(this IEnumerable<T> self) => self.Select((item, index) => (item, index)); // filter where conditions in (Entity Framework) queries based on condition e.g: // AsQueryable().WhereIf(onlyActiveItems, x => x.Active).ToListAsync(); public static IEnumerable<TSource> WhereIf<TSource>(this IEnumerable<TSource> source, bool condition, Func<TSource, bool> predicate) where TSource : class { return condition ? source.Where(predicate) : source; } public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool condition, Expression<Func<TSource, bool>> predicate) where TSource : class { return condition ? source.Where(predicate) : source; } public static IQueryable<TSource> IncludeIf<TSource, TProperty>(this IQueryable<TSource> source, bool condition, Expression<Func<TSource, TProperty>> propertySelector) where TSource : class { return condition ? source.Include(propertySelector) : source; } public static IQueryable<TSource> SkipIf<TSource>(this IQueryable<TSource> source, bool condition, int quantityToSkip) where TSource : class { return condition ? source.Skip(quantityToSkip) : source; } public static IEnumerable<T> SelectRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> recursiveSelector) { foreach (var i in source) { yield return i; var directChildren = recursiveSelector(i); var allChildren = SelectRecursive(directChildren, recursiveSelector); foreach (var c in allChildren) { yield return c; } } } public static IQueryable<TSource> TakeIf<TSource>(this IQueryable<TSource> source, bool condition, int quantityToTake) where TSource : class { return condition ? source.Take(quantityToTake) : source; } public static Dictionary<Y, T> ToDictionarySafe<T, Y>(this IEnumerable<T> items, Func<T, Y> keySelector) => items.GroupBy(x => keySelector(x)).Where(x => x.Key != null).Select(x => x.First()).ToDictionary(x => keySelector(x)); // Comparable with: .GroupBy(x => x.Property).Select(x => x.First()) // but possibly faster and with yield return // update: function exists in dotnet 6 public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) { var seenKeys = new HashSet<TKey>(); foreach (TSource element in source) if (seenKeys.Add(keySelector(element))) yield return element; } public static bool ContainsDuplicates<T>(this IEnumerable<T> enumerable) { var knownKeys = new HashSet<T>(); return enumerable.Any(item => !knownKeys.Add(item)); } public static bool None<T>(this IEnumerable<T> list) => !list.Any(); public static IEnumerable<int> GetRange(int min, int max) { for (var i = min; i <= max; i++) yield return i; } public static List<List<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> list) { return list .SelectMany(inner => inner.Select((item, index) => new { item, index })) .GroupBy(i => i.index, i => i.item) .Select(g => g.ToList()) .ToList(); } }
WhereIf example
// Original: query with separate if statements public async Task<IEnumerable<PurchaseContractExpectedAndDelivered>> GetExpectedAndDeliveredQuantitiesForContract(PurchaseQuantityFilter filter) { using var unitOfWork = GetUnitOfWork(); var query = Query<DmPurchaseContractLine>(unitOfWork); if (filter.PurchaseContractId != null) query = query.Where(x => x.PurchaseContractId == filter.PurchaseContractId) if (filter.PurchaseContractLineId != null) query = query.Where(x => x.Id == filter.PurchaseContractLineId); var selectQuery = query.Select(x => new PurchaseContractExpectedAndDelivered { PurchaseContractId = x.PurchaseContractId, PurchaseContractLineId = x.Id, ExpectedKg = x.WeightKg, DeliveredKg = x.PurchaseShipments.Sum(x => x.WeightKg), DeliveredBoxes = x.PurchaseShipments.Sum(x => x.Boxes), }); return await selectQuery.ToListAsync(); } // With an WhereIf: query as single statement public async Task<IEnumerable<PurchaseContractExpectedAndDelivered>> GetExpectedAndDeliveredQuantitiesForContract(PurchaseQuantityFilter filter) { using var unitOfWork = GetUnitOfWork(); var query = Query<DmPurchaseContractLine>(unitOfWork) .WhereIf(filter.PurchaseContractId != null, x => x.PurchaseContractId == filter.PurchaseContractId) .WhereIf(filter.PurchaseContractLineId != null, x => x.Id == filter.PurchaseContractLineId); .Select(x => new PurchaseContractExpectedAndDelivered { PurchaseContractId = x.PurchaseContractId, PurchaseContractLineId = x.Id, ExpectedKg = x.WeightKg, DeliveredKg = x.PurchaseShipments.Sum(x => x.WeightKg), DeliveredBoxes = x.PurchaseShipments.Sum(x => x.Boxes), }); return await query.ToListAsync(); }
See also:
- https://solidt.eu/site/c-iasyncenumerable/
- https://solidt.eu/site/c-async-selectforeach-with-yield-return/
521600cookie-checkC# LinqHelper