< Summary

Information
Class: MyNet.Collections.EnumerableExtensions
Assembly: MyNet.Collections
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Collections/Extensions/EnumerableExtensions.cs
Tag: 323_28699572109
Line coverage
97%
Covered lines: 93
Uncovered lines: 2
Coverable lines: 95
Total lines: 302
Line coverage: 97.8%
Branch coverage
87%
Covered branches: 47
Total branches: 54
Branch coverage: 87%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
NotNull(...)50%44100%
ToObservableCollection(...)100%22100%
ForEach(...)100%22100%
ForEach(...)100%22100%
Sum(...)100%11100%
Rotate()87.5%88100%
AverageOrDefault(...)100%11100%
AverageOrDefault(...)100%44100%
AverageOrDefault(...)100%44100%
MaxOrDefault(...)100%66100%
MinOrDefault(...)83.33%6690%
RoundRobin()70%101094.11%
GetByIdOrDefault(...)100%44100%
GetById(...)100%22100%
HasId(...)100%11100%
NotNullOrEmpty(...)100%11100%
AverageOrDefault(...)100%11100%
AverageOrDefault(...)100%11100%
AverageOrDefault(...)100%11100%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Collections/Extensions/EnumerableExtensions.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="EnumerableExtensions.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System;
 8using System.Collections.Generic;
 9using System.Collections.ObjectModel;
 10using System.Linq;
 11using MyNet.Primitives;
 12
 13#pragma warning disable IDE0130 // Namespace does not match folder structure
 14namespace MyNet.Collections;
 15#pragma warning restore IDE0130 // Namespace does not match folder structure
 16
 17public static class EnumerableExtensions
 18{
 19    extension<T>(IEnumerable<T> source)
 20    {
 21        /// <summary>
 22        /// Filters out null elements from the sequence and returns a non-nullable enumerable of the remaining items.
 23        /// </summary>
 24        /// <returns>A non-nullable enumerable containing the non-null elements.</returns>
 325        public IEnumerable<T> NotNull() => source.Where(e => e is not null).Select(e => e!);
 26
 27        /// <summary>
 28        /// Converts an <see cref="IEnumerable{T}"/> to an <see cref="ObservableCollection{T}"/>, reusing the source whe
 29        /// </summary>
 30        /// <returns>An observable collection containing the sequence elements.</returns>
 31        public ObservableCollection<T> ToObservableCollection()
 32        {
 633            ArgumentNullException.ThrowIfNull(source);
 34
 635            return source as ObservableCollection<T> ?? new(source);
 36        }
 37
 38        /// <summary>
 39        /// Iterates the sequence and invokes the provided action for each element.
 40        /// </summary>
 41        /// <param name="action">The action to invoke for each element.</param>
 42        public void ForEach(Action<T> action)
 43        {
 344            ArgumentNullException.ThrowIfNull(source);
 345            ArgumentNullException.ThrowIfNull(action);
 46
 2447            foreach (var item in source)
 48            {
 949                action(item);
 50            }
 351        }
 52
 53        /// <summary>
 54        /// Iterates the sequence and invokes the provided action for each element including the element index.
 55        /// </summary>
 56        /// <param name="action">The action to invoke for each element receiving the element and its zero-based index.</
 57        public void ForEach(Action<T, int> action)
 58        {
 359            ArgumentNullException.ThrowIfNull(source);
 360            ArgumentNullException.ThrowIfNull(action);
 61
 362            var i = 0;
 2463            foreach (var item in source)
 64            {
 965                action(item, i);
 966                i++;
 67            }
 368        }
 69
 70        /// <summary>
 71        /// Sums a sequence of <see cref="TimeSpan"/> values projected from the source.
 72        /// </summary>
 73        /// <param name="selector">A selector that returns a <see cref="TimeSpan"/> for each element.</param>
 74        /// <returns>The aggregated <see cref="TimeSpan"/>.</returns>
 75        public TimeSpan Sum(Func<T, TimeSpan> selector)
 76        {
 377            ArgumentNullException.ThrowIfNull(source);
 378            ArgumentNullException.ThrowIfNull(selector);
 79
 380            return source.Aggregate(TimeSpan.Zero, (current, item) => current + selector(item));
 81        }
 82
 83        /// <summary>
 84        /// Rotates the sequence by the specified offset, moving the first <paramref name="offset"/> elements to the end
 85        /// </summary>
 86        /// <param name="offset">The number of elements to skip from the start.</param>
 87        /// <returns>A rotated sequence.</returns>
 88        public IEnumerable<T> Rotate(int offset)
 89        {
 990            var list = source as IList<T> ?? [.. source];
 91
 992            var count = list.Count;
 993            if (count == 0)
 394                yield break;
 95
 696            offset %= count;
 697            if (offset < 0)
 398                offset += count;
 99
 60100            for (var i = 0; i < count; i++)
 24101                yield return list[(i + offset) % count];
 6102        }
 103
 104        /// <summary>
 105        /// Returns the average of a projected integer sequence or <paramref name="defaultValue"/> when the sequence is 
 106        /// </summary>
 107        public double AverageOrDefault(Func<T, int> selector, int defaultValue = 0)
 9108            => source.AverageOrDefault(x => (double)selector(x), defaultValue);
 109
 110        /// <summary>
 111        /// Returns the average of a projected double sequence or <paramref name="defaultValue"/> when the sequence is e
 112        /// </summary>
 113        public double AverageOrDefault(Func<T, double> selector, double defaultValue = 0)
 114        {
 15115            ArgumentNullException.ThrowIfNull(source);
 15116            ArgumentNullException.ThrowIfNull(selector);
 117
 15118            var sum = 0.0d;
 15119            var count = 0;
 120
 84121            foreach (var item in source)
 122            {
 27123                sum += selector(item);
 27124                count++;
 125            }
 126
 15127            return count == 0 ? defaultValue : sum / count;
 128        }
 129
 130        /// <summary>
 131        /// Returns the average of a projected decimal sequence or <paramref name="defaultValue"/> when the sequence is 
 132        /// </summary>
 133        public decimal AverageOrDefault(Func<T, decimal> selector, decimal defaultValue = 0)
 134        {
 6135            ArgumentNullException.ThrowIfNull(source);
 6136            ArgumentNullException.ThrowIfNull(selector);
 137
 6138            var sum = 0.0m;
 6139            var count = 0;
 140
 30141            foreach (var item in source)
 142            {
 9143                sum += selector(item);
 9144                count++;
 145            }
 146
 6147            return count == 0 ? defaultValue : sum / count;
 148        }
 149
 150        /// <summary>
 151        /// Returns the maximum projected value from the sequence or <paramref name="defaultValue"/> when the sequence i
 152        /// </summary>
 153        public TResult MaxOrDefault<TResult>(Func<T, TResult> selector, TResult defaultValue = default)
 154            where TResult : struct, IComparable
 155        {
 6156            ArgumentNullException.ThrowIfNull(source);
 157
 6158            using var e = source.GetEnumerator();
 6159            if (!e.MoveNext())
 3160                return defaultValue;
 161
 3162            var max = selector(e.Current);
 163
 9164            while (e.MoveNext())
 165            {
 6166                var current = selector(e.Current);
 6167                if (current.CompareTo(max) > 0)
 3168                    max = current;
 169            }
 170
 3171            return max;
 172        }
 173
 174        /// <summary>
 175        /// Returns the minimum projected value from the sequence or <paramref name="defaultValue"/> when the sequence i
 176        /// </summary>
 177        public TResult MinOrDefault<TResult>(Func<T, TResult> selector, TResult defaultValue = default)
 178            where TResult : struct, IComparable
 179        {
 6180            ArgumentNullException.ThrowIfNull(source);
 181
 6182            using var e = source.GetEnumerator();
 6183            if (!e.MoveNext())
 3184                return defaultValue;
 185
 3186            var min = selector(e.Current);
 187
 9188            while (e.MoveNext())
 189            {
 6190                var current = selector(e.Current);
 6191                if (current.CompareTo(min) < 0)
 0192                    min = current;
 193            }
 194
 3195            return min;
 196        }
 197
 198        /// <summary>
 199        /// Generates round-robin pairings for the sequence items. If the number of items is odd, a default placeholder 
 200        /// </summary>
 201        /// <returns>A collection of rounds, each round being a sequence of pairs.</returns>
 202        public IEnumerable<IEnumerable<(T Item1, T Item2)>> RoundRobin()
 203        {
 3204            var list = source.ToList();
 205
 3206            if (list.Count % 2 != 0)
 0207                list.Add(default!);
 208
 3209            var n = list.Count;
 3210            var rounds = n - 1;
 211
 24212            for (var r = 0; r < rounds; r++)
 213            {
 9214                var round = new List<(T, T)>(n / 2);
 215
 54216                for (var i = 0; i < n / 2; i++)
 217                {
 18218                    var a = list[i];
 18219                    var b = list[n - 1 - i];
 220
 18221                    if (a is not null && b is not null)
 18222                        round.Add((a, b));
 223                }
 224
 9225                yield return round;
 226
 227                // rotate (circle method)
 9228                var last = list[^1];
 229
 9230                list.RemoveAt(list.Count - 1);
 9231                list.Insert(1, last);
 232            }
 3233        }
 234    }
 235
 236    extension<T, TId>(IEnumerable<T> source)
 237        where T : IIdentifiable<TId>
 238    {
 239        /// <summary>
 240        /// Finds an item by its identifier or returns the default when not found.
 241        /// </summary>
 242        /// <param name="id">The identifier to search for.</param>
 243        /// <returns>The matching element or <c>null</c> if not found.</returns>
 244        public T? GetByIdOrDefault(TId? id)
 245        {
 12246            ArgumentNullException.ThrowIfNull(source);
 247
 48248            foreach (var item in source)
 249            {
 15250                if (Equals(item.Id, id))
 6251                    return item;
 252            }
 253
 6254            return default;
 255        }
 256
 257        /// <summary>
 258        /// Finds an item by its identifier or throws when not found.
 259        /// </summary>
 260        public T GetById(TId id)
 261        {
 6262            var result = source.GetByIdOrDefault(id);
 263
 6264            return result ?? throw new KeyNotFoundException($"Id '{id}' not found.");
 265        }
 266
 267        /// <summary>
 268        /// Determines whether any element in the sequence has the specified identifier.
 269        /// </summary>
 270        public bool HasId(TId id)
 271        {
 6272            ArgumentNullException.ThrowIfNull(source);
 273
 6274            return source.Any(item => Equals(item.Id, id));
 275        }
 276    }
 277
 278    extension(IEnumerable<string> source)
 279    {
 280        /// <summary>
 281        /// Filters out null or empty string elements from the sequence and returns a non-nullable enumerable of the rem
 282        /// </summary>
 283        /// <returns>A non-nullable enumerable containing the non-null and non-empty string elements.</returns>
 3284        public IEnumerable<string> NotNullOrEmpty() => source.Where(e => !string.IsNullOrWhiteSpace(e)).Select(e => e);
 285    }
 286
 287    /// <summary>
 288    /// Returns the average of a sequence of integers or 0 when the sequence is empty.
 289    /// </summary>
 6290    public static double AverageOrDefault(this IEnumerable<int> source) => source.AverageOrDefault(x => x);
 291
 292    /// <summary>
 293    /// Returns the average of a sequence of doubles or 0 when the sequence is empty.
 294    /// </summary>
 3295    public static double AverageOrDefault(this IEnumerable<double> source) => source.AverageOrDefault(x => x);
 296
 297    /// <summary>
 298    /// Returns the average of a sequence of decimals or 0 when the sequence is empty.
 299    /// </summary>
 3300    public static decimal AverageOrDefault(this IEnumerable<decimal> source) => source.AverageOrDefault(x => x);
 301}
 302