using System; using System.Collections.Generic; using System.Linq; namespace ICSharpCode.Decompiler.Util { static class CollectionExtensions { public static void Deconstruct(this KeyValuePair pair, out K key, out V value) { key = pair.Key; value = pair.Value; } public static HashSet ToHashSet(this IEnumerable input) { return new HashSet(input); } public static IEnumerable SkipLast(this IReadOnlyCollection input, int count) { return input.Take(input.Count - count); } public static T PopOrDefault(this Stack stack) { if (stack.Count == 0) return default(T); return stack.Pop(); } public static T PeekOrDefault(this Stack stack) { if (stack.Count == 0) return default(T); return stack.Peek(); } public static int MaxOrDefault(this IEnumerable input, Func selector, int defaultValue = 0) { int max = defaultValue; foreach (var element in input) { int value = selector(element); if (value > max) max = value; } return max; } public static void AddRange(this ICollection collection, IEnumerable input) { foreach (T item in input) collection.Add(item); } /// /// Equivalent to collection.Select(func).ToArray(), but more efficient as it makes /// use of the input collection's known size. /// public static U[] SelectArray(this ICollection collection, Func func) { U[] result = new U[collection.Count]; int index = 0; foreach (var element in collection) { result[index++] = func(element); } return result; } /// /// Equivalent to collection.Select(func).ToList(), but more efficient as it makes /// use of the input collection's known size. /// public static List SelectList(this ICollection collection, Func func) { List result = new List(collection.Count); foreach (var element in collection) { result.Add(func(element)); } return result; } public static IEnumerable SelectWithIndex(this IEnumerable source, Func func) { int index = 0; foreach (var element in source) yield return func(index++, element); } /// /// The merge step of merge sort. /// public static IEnumerable Merge(this IEnumerable input1, IEnumerable input2, Comparison comparison) { var enumA = input1.GetEnumerator(); var enumB = input2.GetEnumerator(); bool moreA = enumA.MoveNext(); bool moreB = enumB.MoveNext(); while (moreA && moreB) { if (comparison(enumA.Current, enumB.Current) <= 0) { yield return enumA.Current; moreA = enumA.MoveNext(); } else { yield return enumB.Current; moreB = enumB.MoveNext(); } } while (moreA) { yield return enumA.Current; moreA = enumA.MoveNext(); } while (moreB) { yield return enumB.Current; moreB = enumB.MoveNext(); } } /// /// Returns the minimum element. /// /// The input sequence is empty public static T MinBy(this IEnumerable source, Func keySelector) where K : IComparable { return source.MinBy(keySelector, Comparer.Default); } /// /// Returns the minimum element. /// /// The input sequence is empty public static T MinBy(this IEnumerable source, Func keySelector, IComparer keyComparer) { if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); if (keyComparer == null) keyComparer = Comparer.Default; using (var enumerator = source.GetEnumerator()) { if (!enumerator.MoveNext()) throw new InvalidOperationException("Sequence contains no elements"); T minElement = enumerator.Current; K minKey = keySelector(minElement); while (enumerator.MoveNext()) { T element = enumerator.Current; K key = keySelector(element); if (keyComparer.Compare(key, minKey) < 0) { minElement = element; minKey = key; } } return minElement; } } /// /// Returns the maximum element. /// /// The input sequence is empty public static T MaxBy(this IEnumerable source, Func keySelector) where K : IComparable { return source.MaxBy(keySelector, Comparer.Default); } /// /// Returns the maximum element. /// /// The input sequence is empty public static T MaxBy(this IEnumerable source, Func keySelector, IComparer keyComparer) { if (source == null) throw new ArgumentNullException(nameof(source)); if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); if (keyComparer == null) keyComparer = Comparer.Default; using (var enumerator = source.GetEnumerator()) { if (!enumerator.MoveNext()) throw new InvalidOperationException("Sequence contains no elements"); T maxElement = enumerator.Current; K maxKey = keySelector(maxElement); while (enumerator.MoveNext()) { T element = enumerator.Current; K key = keySelector(element); if (keyComparer.Compare(key, maxKey) > 0) { maxElement = element; maxKey = key; } } return maxElement; } } public static void RemoveLast(this IList list) { if (list == null) throw new ArgumentNullException(nameof(list)); list.RemoveAt(list.Count - 1); } } }