From f674d4c60d34269ea7a9fcebeba870a040ec53e6 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Thu, 7 Jun 2018 18:16:24 -0400 Subject: [PATCH] refactor: Separating iterators from validation --- .../Extensions/EnumerableExtensions.cs | 185 +++++++++++++++--- 1 file changed, 161 insertions(+), 24 deletions(-) diff --git a/ICD.Common.Utils/Extensions/EnumerableExtensions.cs b/ICD.Common.Utils/Extensions/EnumerableExtensions.cs index 55d5653..d8cd021 100644 --- a/ICD.Common.Utils/Extensions/EnumerableExtensions.cs +++ b/ICD.Common.Utils/Extensions/EnumerableExtensions.cs @@ -42,10 +42,8 @@ namespace ICD.Common.Utils.Extensions if (predicate == null) throw new ArgumentNullException("predicate"); - foreach (T item in extends.Where(predicate)) - return item; - - return defaultItem; + T output; + return extends.TryFirst(predicate, out output) ? output : defaultItem; } /// @@ -309,9 +307,21 @@ namespace ICD.Common.Utils.Extensions if (match == null) throw new ArgumentNullException("match"); + return FindIndicesIterator(extends, match); + } + + /// + /// Returns the indices that match the predicate. + /// + /// + /// + /// + /// + private static IEnumerable FindIndicesIterator(IEnumerable sequence, Predicate match) + { int index = 0; - foreach (T item in extends) + foreach (T item in sequence) { if (match(item)) yield return index; @@ -405,8 +415,21 @@ namespace ICD.Common.Utils.Extensions if (extends == null) throw new ArgumentNullException("extends"); + return PrependIterator(extends, item); + } + + /// + /// Prepends the item to the start of the sequence. + /// + /// + /// + /// + /// + private static IEnumerable PrependIterator(IEnumerable sequence, T item) + { yield return item; - foreach (T next in extends) + + foreach (T next in sequence) yield return next; } #endif @@ -427,9 +450,22 @@ namespace ICD.Common.Utils.Extensions if (items == null) throw new ArgumentNullException("items"); + return PrependManyIterator(extends, items); + } + + /// + /// Prepends the items to the start of the sequence. + /// + /// + /// + /// + /// + private static IEnumerable PrependManyIterator(IEnumerable sequence, params T[] items) + { foreach (T item in items) yield return item; - foreach (T each in extends) + + foreach (T each in sequence) yield return each; } @@ -446,8 +482,21 @@ namespace ICD.Common.Utils.Extensions if (extends == null) throw new ArgumentNullException("extends"); - foreach (T first in extends) + return AppendIterator(extends, item); + } + + /// + /// Appends the item to the end of the sequence. + /// + /// + /// + /// + /// + private static IEnumerable AppendIterator(IEnumerable sequence, T item) + { + foreach (T first in sequence) yield return first; + yield return item; } #endif @@ -468,8 +517,21 @@ namespace ICD.Common.Utils.Extensions if (items == null) throw new ArgumentNullException("items"); - foreach (T each in extends) + return AppendManyIterator(extends, items); + } + + /// + /// Appends the items to the end of the sequence. + /// + /// + /// + /// + /// + private static IEnumerable AppendManyIterator(IEnumerable sequence, params T[] items) + { + foreach (T each in sequence) yield return each; + foreach (T item in items) yield return item; } @@ -487,9 +549,21 @@ namespace ICD.Common.Utils.Extensions if (extends == null) throw new ArgumentNullException("extends"); + return PadRightIterator(extends, count); + } + + /// + /// Pads the given sequence to the given count size with default items. + /// + /// + /// + /// + /// + private static IEnumerable PadRightIterator(IEnumerable sequence, int count) + { int index = 0; - foreach (T item in extends) + foreach (T item in sequence) { yield return item; index++; @@ -801,7 +875,18 @@ namespace ICD.Common.Utils.Extensions if (extends == null) throw new ArgumentNullException("extends"); - using (IEnumerator enumerator = extends.GetEnumerator()) + return PartitionIterator(extends, partitionSize); + } + + /// + /// Partitions a sequence into sequences of the given length. + /// + /// + /// + /// + private static IEnumerable> PartitionIterator(IEnumerable sequence, int partitionSize) + { + using (IEnumerator enumerator = sequence.GetEnumerator()) { while (enumerator.MoveNext()) yield return YieldBatchElements(enumerator, partitionSize - 1); @@ -826,9 +911,9 @@ namespace ICD.Common.Utils.Extensions /// /// Wraps this object instance into an IEnumerable consisting of a single item. /// - /// Type of the object. - /// The instance that will be wrapped. - /// An IEnumerable<T> consisting of a single item. + /// Type of the object. + /// The instance that will be wrapped. + /// An IEnumerable<T> consisting of a single item. public static IEnumerable Yield(this T item) { yield return item; @@ -841,6 +926,20 @@ namespace ICD.Common.Utils.Extensions /// /// public static IEnumerable GetAdjacentPairs(this IEnumerable extends) + { + if (extends == null) + throw new ArgumentNullException("extends"); + + return GetAdjacentPairsIterator(extends); + } + + /// + /// Given a sequence [A, B, C] returns a sequence [[A, B], [B, C]] + /// + /// + /// + /// + private static IEnumerable GetAdjacentPairsIterator(IEnumerable extends) { T previous = default(T); bool first = true; @@ -848,7 +947,7 @@ namespace ICD.Common.Utils.Extensions foreach (T item in extends) { if (!first) - yield return new[] {previous, item}; + yield return new[] { previous, item }; first = false; previous = item; @@ -932,18 +1031,22 @@ namespace ICD.Common.Utils.Extensions { if (!sourceIterator.MoveNext()) throw new InvalidOperationException("Sequence contains no elements"); + TSource min = sourceIterator.Current; TKey minKey = selector(min); + while (sourceIterator.MoveNext()) { TSource candidate = sourceIterator.Current; TKey candidateProjected = selector(candidate); + if (comparer.Compare(candidateProjected, minKey) >= 0) continue; min = candidate; minKey = candidateProjected; } + return min; } } @@ -1017,16 +1120,33 @@ namespace ICD.Common.Utils.Extensions if (comparer == null) throw new ArgumentNullException("comparer"); + return ConsolidateIterator(extends, comparer); + } + + /// + /// Skips duplicate, consecutive items. + /// E.g. + /// [1, 2, 2, 3, 1, 1] + /// Becomes + /// [1, 2, 3, 1] + /// + /// + /// + /// + /// + private static IEnumerable ConsolidateIterator(IEnumerable sequence, IComparer comparer) + { bool first = true; T last = default(T); - foreach (T item in extends) + foreach (T item in sequence) { if (!first && comparer.Compare(last, item) == 0) continue; first = false; last = item; + yield return item; } } @@ -1141,23 +1261,40 @@ namespace ICD.Common.Utils.Extensions /// /// /// - /// - /// + /// + /// /// /// - public static IEnumerable Zip(this IEnumerable first, - IEnumerable second, + public static IEnumerable Zip(this IEnumerable extends, + IEnumerable other, Func callback) { - if (first == null) - throw new ArgumentNullException("first"); + if (extends == null) + throw new ArgumentNullException("extends"); - if (second == null) - throw new ArgumentNullException("second"); + if (other == null) + throw new ArgumentNullException("other"); if (callback == null) throw new ArgumentNullException("callback"); + return ZipIterator(extends, other, callback); + } + + /// + /// Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results. + /// + /// + /// + /// + /// + /// + /// + /// + private static IEnumerable ZipIterator(IEnumerable first, + IEnumerable second, + Func callback) + { using (IEnumerator enumerator1 = first.GetEnumerator()) { using (IEnumerator enumerator2 = second.GetEnumerator())