// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; namespace EpicGames.Core { /// /// Extension methods for /// public static class EnumerableExtensions { /// /// Dispose all elements in a sequence /// /// Sequence of elements to dispose public static void DisposeAll(this IEnumerable sequence) { foreach (IDisposable element in sequence) { element.Dispose(); } } /// /// Split the sequence into batches of at most the given size /// /// The element type /// Sequence to split into batches /// Maximum size of each batch /// Sequence of batches public static IEnumerable> Batch(this IEnumerable sequence, int batchSize) { List elements = new List(batchSize); foreach (TElement element in sequence) { elements.Add(element); if (elements.Count == batchSize) { yield return elements; elements.Clear(); } } if (elements.Count > 0) { yield return elements; } } /// /// Finds the minimum element by a given field /// /// /// /// /// public static TElement MinBy(this IEnumerable sequence, Func selector) { IEnumerator enumerator = sequence.GetEnumerator(); if (!enumerator.MoveNext()) { throw new Exception("Collection is empty"); } TElement minElement = enumerator.Current; int minValue = selector(minElement); while (enumerator.MoveNext()) { int value = selector(enumerator.Current); if (value < minValue) { minElement = enumerator.Current; } } return minElement; } /// /// Finds the maximum element by a given field /// /// /// /// /// public static TElement MaxBy(this IEnumerable sequence, Func selector) { IEnumerator enumerator = sequence.GetEnumerator(); if (!enumerator.MoveNext()) { throw new Exception("Collection is empty"); } TElement maxElement = enumerator.Current; int maxValue = selector(maxElement); while (enumerator.MoveNext()) { int value = selector(enumerator.Current); if (value > maxValue) { maxElement = enumerator.Current; } } return maxElement; } /// /// Zips two dictionaries, returning a sequence of keys with the old and new values (or null if they have been removed). /// /// Common key between the two dictionaries /// Type of values in the first dictionary /// Type of values in the second dictionary /// The first dictionary /// The second dictionary /// Sequence of key/value pairs from each dictionary public static IEnumerable<(TKey, TOldValue?, TNewValue?)> Zip(this IReadOnlyDictionary? oldDictionary, IReadOnlyDictionary? newDictionary) where TKey : notnull where TOldValue : class where TNewValue : class { if (newDictionary != null) { foreach ((TKey key, TNewValue newValue) in newDictionary) { TOldValue? oldValue; if (oldDictionary == null || !oldDictionary.TryGetValue(key, out oldValue)) { yield return (key, null, newValue); } else { yield return (key, oldValue, newValue); } } } if (oldDictionary != null) { foreach ((TKey key, TOldValue oldValue) in oldDictionary) { if (newDictionary == null || !newDictionary.ContainsKey(key)) { yield return (key, oldValue, null); } } } } } }