< Summary

Information
Class: MoreStructures.Lists.Counting.DictionaryBasedOccurrencesCounter
Assembly: MoreStructures
File(s): /home/runner/work/MoreStructures/MoreStructures/MoreStructures/Lists/Counting/DictionaryBasedOccurrencesCounter.cs
Line coverage
100%
Covered lines: 21
Uncovered lines: 0
Coverable lines: 21
Total lines: 55
Line coverage: 100%
Branch coverage
100%
Covered branches: 14
Total branches: 14
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
Count(...)100%14100%

File(s)

/home/runner/work/MoreStructures/MoreStructures/MoreStructures/Lists/Counting/DictionaryBasedOccurrencesCounter.cs

#LineLine coverage
 1namespace MoreStructures.Lists.Counting;
 2
 3/// <summary>
 4/// An implementation of <see cref="IOccurrencesCounter"/> which uses a <see cref="Dictionary{TKey, TValue}"/> to build
 5/// the two-level <see cref="IDictionary{TKey, TValue}"/> of occurrences, indexed by distinct item values and index.
 6/// </summary>
 7public class DictionaryBasedOccurrencesCounter : IOccurrencesCounter
 8{
 9    /// <inheritdoc path="//*[not(self::remarks or self::typeparam)]"/>
 10    /// <typeparam name="T">
 11    /// The type of items of <paramref name="enumerable"/>.
 12    /// </typeparam>
 13    /// <remarks>
 14    /// Perform counting by keeping a <see cref="IDictionary{TKey, TValue}"/> of the current number of occurrences per
 15    /// item encountered, by distinct value of <typeparamref name="T"/> and index, while enumerating
 16    /// <paramref name="enumerable"/>.
 17    /// <br/>
 18    /// Both Time Complexity and Space Complexity are O(n * sigma), where n = number of items in
 19    /// <paramref name="enumerable"/> and sigma = number of the alphabet of <paramref name="enumerable"/>, i.e. the
 20    /// number of distinct items of type <typeparamref name="T"/> in <paramref name="enumerable"/>.
 21    /// </remarks>
 22    public IDictionary<T, IDictionary<int, int>> Count<T>(IEnumerable<T> enumerable)
 23        where T: notnull
 2924    {
 2925        var lastIndexSetByItem = new Dictionary<T, int> { };
 2926        var counts = new Dictionary<T, IDictionary<int, int>> { };
 2927        var index = 0;
 61528        foreach (var item in enumerable)
 26429        {
 26430            if (!counts.TryGetValue(item, out var countsOfItem))
 10031                counts[item] = countsOfItem = new Dictionary<int, int> { };
 32
 33            // Set the count for item at the current index, to be one more than the previous index (or 1)
 26434            countsOfItem[index] = countsOfItem.ContainsKey(index - 1) ? countsOfItem[index - 1] + 1 : 1;
 35
 36            // Set the counts for all indexes between index since the last update of counts[item] and the current one.
 26437            if (!lastIndexSetByItem.TryGetValue(item, out var lastIndexSet))
 10038                lastIndexSet = -1;
 39
 156040            for (var priorIndex = lastIndexSet + 1; priorIndex < index; priorIndex++)
 51641                countsOfItem[priorIndex] = countsOfItem[index] - 1;
 42
 26443            lastIndexSetByItem[item] = index;
 44
 45            // Set the count for all other items at the current index, to be the same as for previous index (or 0)
 252046            foreach (var otherItem in counts.Keys)
 86447                if (!Equals(otherItem, item))
 60048                    counts[otherItem][index] = counts[otherItem][index - 1];
 49
 26450            index++;
 26451        }
 52
 2953        return counts;
 2954    }
 55}