< Summary - SonghayCore

Information
Class: Songhay.Extensions.IEnumerableOfTExtensions
Assembly: SonghayCore
File(s): /home/rasx/sourceRoot/SonghayCore/SonghayCore/Extensions/IEnumerableOfTExtensions.cs
Line coverage
10%
Covered lines: 8
Uncovered lines: 66
Coverable lines: 74
Total lines: 222
Line coverage: 10.8%
Branch coverage
19%
Covered branches: 8
Total branches: 42
Branch coverage: 19%
Method coverage

Method coverage is only available for sponsors.

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
Flatten(...)0%80%
Flatten(...)100%10%
ForEachInEnumerable(...)100%8100%
ForEachInEnumerable(...)0%60%
Partition()0%80%
SelectWithPrevious()0%40%
ToCollection(...)0%20%
ToDisplayString(...)100%10%
ToDisplayString(...)0%60%

File(s)

/home/rasx/sourceRoot/SonghayCore/SonghayCore/Extensions/IEnumerableOfTExtensions.cs

#LineLine coverage
 1namespace Songhay.Extensions;
 2
 3/// <summary>
 4/// Extensions of <see cref="IEnumerable{T}"/>.
 5/// </summary>
 6/// <remarks>
 7/// When this ‘greatest hits collection’ is found to be limited,
 8/// upgrade to MoreLinq [ see https://github.com/morelinq/MoreLINQ ]
 9/// </remarks>
 10// ReSharper disable once InconsistentNaming
 11public static class IEnumerableOfTExtensions
 12{
 13    /// <summary>
 14    /// Flattens the specified source.
 15    /// </summary>
 16    /// <typeparam name="TSource">The type of the source.</typeparam>
 17    /// <param name="source">The source.</param>
 18    /// <param name="childGetter">The child getter.</param>
 19    /// <remarks>
 20    /// When <c>source</c> is not already an array,
 21    /// this member will mercilessly allocate a snapshot of <c>TSource[]</c>.
 22    /// To avoid this memory pressure, upgrade to the <c>Flatten</c> method
 23    /// of MoreLinq [ see https://github.com/morelinq/MoreLINQ/blob/master/MoreLinq/Flatten.cs#L91 ]
 24    /// </remarks>
 25    public static IEnumerable<TSource> Flatten<TSource>(this IEnumerable<TSource>? source,
 26        Func<TSource, IEnumerable<TSource>>? childGetter)
 027    {
 028        if (source == null) return Enumerable.Empty<TSource>();
 029        var snapshot = source as TSource[] ?? source.ToArray();
 30
 031        var flattenedList = new List<TSource>(snapshot);
 32
 033        snapshot.ForEachInEnumerable(i =>
 034        {
 035            var children = childGetter?.Invoke(i);
 036            if (children != null) flattenedList.AddRange(children.Flatten(childGetter));
 037        });
 38
 039        return flattenedList;
 040    }
 41
 42    /// <summary>
 43    /// Flattens the specified source.
 44    /// </summary>
 45    /// <typeparam name="TSource">The type of the source.</typeparam>
 46    /// <param name="source">The source.</param>
 47    /// <param name="childGetter">The child getter.</param>
 48    /// <param name="flattenedHead">The flattened head.</param>
 49    public static IEnumerable<TSource> Flatten<TSource>(this IEnumerable<TSource> source,
 50        Func<TSource, IEnumerable<TSource>> childGetter, TSource flattenedHead) =>
 051        new[] {flattenedHead}.Concat(source.Flatten(childGetter));
 52
 53    /// <summary>
 54    /// Performs the <see cref="Action"/>
 55    /// on each item in the enumerable object.
 56    /// </summary>
 57    /// <typeparam name="TEnumerable">The type of the enumerable.</typeparam>
 58    /// <param name="enumerable">The enumerable.</param>
 59    /// <param name="action">The action.</param>
 60    /// <remarks>
 61    /// “I am philosophically opposed to providing such a method, for two reasons.
 62    /// …The first reason is that doing so violates the functional programming principles
 63    /// that all the other sequence operators are based upon. Clearly the sole purpose of a call
 64    /// to this method is to cause side effects.”
 65    /// —Eric Lippert, “foreach” vs “ForEach” [http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach
 66    /// </remarks>
 67    public static void ForEachInEnumerable<TEnumerable>(this IEnumerable<TEnumerable>? enumerable,
 68        Action<TEnumerable>? action)
 1722969    {
 1722970        if (enumerable == null) return;
 1722971        if (action == null) return;
 72
 6939973        foreach (var item in enumerable)
 885674        {
 885675            action?.Invoke(item);
 885676        }
 1722977    }
 78
 79    /// <summary>
 80    /// Performs the <see cref="Action"/>
 81    /// on each item in the enumerable object.
 82    /// </summary>
 83    /// <typeparam name="TEnumerable">The type of the enumerable.</typeparam>
 84    /// <param name="enumerable">The enumerable.</param>
 85    /// <param name="action">The action.</param>
 86    /// <remarks>
 87    /// This member is ruthlessly derived from <c>MoreLinq.ForEach{T}</c>
 88    /// [ see https://github.com/morelinq/MoreLINQ/blob/master/MoreLinq/ForEach.cs#L50 ].
 89    /// </remarks>
 90    public static void ForEachInEnumerable<TEnumerable>(this IEnumerable<TEnumerable>? enumerable,
 91        Action<TEnumerable, int>? action)
 092    {
 093        if (enumerable == null) return;
 094        if (action == null) return;
 95
 096        var index = 0;
 097        foreach (var element in enumerable)
 098        {
 099            action.Invoke(element, index++);
 0100        }
 0101    }
 102
 103    /// <summary>
 104    /// Partitions the specified source.
 105    /// </summary>
 106    /// <typeparam name="T"></typeparam>
 107    /// <param name="source">The source.</param>
 108    /// <param name="size">The size.</param>
 109    /// <remarks>
 110    /// This member is by Jon Skeet.
 111    /// [http://stackoverflow.com/questions/438188/split-a-collection-into-n-parts-with-linq]
 112    /// </remarks>
 113    public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> source, int size)
 0114    {
 0115        T[]? array = null;
 116
 0117        int count = 0;
 0118        foreach (T item in source)
 0119        {
 0120            if (array == null)
 0121            {
 0122                array = new T[size];
 0123            }
 124
 0125            array[count] = item;
 0126            count++;
 0127            if (count == size)
 0128            {
 0129                yield return new ReadOnlyCollection<T>(array);
 0130                array = null;
 0131                count = 0;
 0132            }
 0133        }
 134
 0135        if (array == null) yield break;
 136
 0137        Array.Resize(ref array, count);
 0138        yield return new ReadOnlyCollection<T>(array);
 0139    }
 140
 141    /// <summary>
 142    /// Projects the previous item with the current item.
 143    /// </summary>
 144    /// <typeparam name="TSource">The type of the source.</typeparam>
 145    /// <typeparam name="TResult">The type of the result.</typeparam>
 146    /// <param name="source">The source.</param>
 147    /// <param name="projection">The projection.</param>
 148    /// <remarks>
 149    /// “This enables you to perform your projection using only a single pass of the source sequence,
 150    /// which is always a bonus (imagine running it over a large log file).
 151    /// Note that it will project a sequence of length n into a sequence of length n-1—
 152    /// you may want to prepend a ‘dummy’ first element, for example. (Or change the method to include one.)
 153    /// Here’s an example of how you'd use it:
 154    /// <code>
 155    /// var query = list.SelectWithPrevious((prev, cur) =&gt; new { ID = cur.ID, Date = cur.Date, DateDiff = (cur.Date -
 156    /// </code>
 157    /// Note that this will include the final result of one ID with the first result of the next ID…
 158    /// you may wish to group your sequence by ID first.”
 159    /// —Jon Skeet, “Calculate difference from previous item with LINQ”
 160    /// [http://stackoverflow.com/questions/3683105/calculate-difference-from-previous-item-with-linq/3683217#3683217]
 161    /// </remarks>
 162    public static IEnumerable<TResult> SelectWithPrevious<TSource, TResult>(this IEnumerable<TSource> source,
 163        Func<TSource, TSource, TResult> projection)
 0164    {
 0165        using var iterator = source.GetEnumerator();
 166
 0167        if (!iterator.MoveNext())
 0168        {
 0169            yield break;
 170        }
 171
 0172        TSource previous = iterator.Current;
 0173        while (iterator.MoveNext())
 0174        {
 0175            yield return projection(previous, iterator.Current);
 0176            previous = iterator.Current;
 0177        }
 0178    }
 179
 180    /// <summary>
 181    /// Converts the <see cref="IEnumerable{TEnumerable}"/>
 182    /// into <see cref="ICollection{TEnumerable}"/>.
 183    /// </summary>
 184    /// <typeparam name="TEnumerable"></typeparam>
 185    /// <param name="enumerable"></param>
 186    /// <remarks>
 187    /// For details, see “When To Use IEnumerable, ICollection, IList And List”
 188    /// [http://www.claudiobernasconi.ch/2013/07/22/when-to-use-ienumerable-icollection-ilist-and-list/]
 189    /// </remarks>
 190    public static ICollection<TEnumerable> ToCollection<TEnumerable>(this IEnumerable<TEnumerable>? enumerable) =>
 0191        enumerable == null ? Enumerable.Empty<TEnumerable>().ToList() : enumerable.ToList();
 192
 193    /// <summary>
 194    /// Converts the <see cref="IEnumerable{TSource}"/> into a display string.
 195    /// </summary>
 196    /// <typeparam name="TSource">The type of the source.</typeparam>
 197    /// <param name="data">The source.</param>
 198    public static string ToDisplayString<TSource>(this IEnumerable<TSource> data) where TSource : class =>
 0199        data.ToDisplayString(indent: 0);
 200
 201    /// <summary>
 202    /// Converts the <see cref="IEnumerable{TSource}"/> into a display string.
 203    /// </summary>
 204    /// <typeparam name="TSource">The type of the source.</typeparam>
 205    /// <param name="source">The source.</param>
 206    /// <param name="indent">The indent.</param>
 207    public static string ToDisplayString<TSource>(this IEnumerable<TSource> source, byte indent) where TSource : class
 0208    {
 0209        var indentation = string.Join(string.Empty, Enumerable.Repeat(" ", indent).ToArray());
 0210        var builder = new StringBuilder();
 211
 0212        var snapshot = source as TSource[] ?? source.ToArray();
 213
 0214        if (snapshot.Any()) builder.Append($"{indentation}{snapshot.Length} child items:");
 215
 0216        snapshot.ForEachInEnumerable(i => builder.Append($"{Environment.NewLine}{indentation}{i}"));
 217
 0218        if (builder.Length > 0) builder.AppendLine();
 219
 0220        return builder.ToString();
 0221    }
 222}