namespace UnityHelpers.Core.Extension { using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; public static class DictionaryExtensions { public static V GetOrAdd( this IDictionary dictionary, K key, Func valueProducer ) { if (dictionary is ConcurrentDictionary concurrentDictionary) { return concurrentDictionary.GetOrAdd( key, static (_, existing) => existing(), valueProducer ); } if (dictionary.TryGetValue(key, out V result)) { return result; } return dictionary[key] = valueProducer(); } public static V GetOrAdd( this IDictionary dictionary, K key, Func valueProducer ) { if (dictionary is ConcurrentDictionary concurrentDictionary) { return concurrentDictionary.GetOrAdd(key, valueProducer); } if (dictionary.TryGetValue(key, out V result)) { return result; } return dictionary[key] = valueProducer(key); } public static V GetOrElse( this IReadOnlyDictionary dictionary, K key, Func valueProducer ) { if (dictionary.TryGetValue(key, out V value)) { return value; } return valueProducer.Invoke(); } public static V GetOrElse( this IReadOnlyDictionary dictionary, K key, Func valueProducer ) { if (dictionary.TryGetValue(key, out V value)) { return value; } return valueProducer.Invoke(key); } public static V GetOrAdd(this IDictionary dictionary, K key) where V : new() { if (dictionary is ConcurrentDictionary concurrentDictionary) { return concurrentDictionary.AddOrUpdate( key, _ => new V(), (_, existing) => existing ); } if (dictionary.TryGetValue(key, out V result)) { return result; } return dictionary[key] = new V(); } public static V GetOrElse(this IReadOnlyDictionary dictionary, K key, V value) { return GetOrElse(dictionary, key, () => value); } public static V AddOrUpdate( this IDictionary dictionary, K key, Func creator, Func updater ) { if (dictionary is ConcurrentDictionary concurrentDictionary) { return concurrentDictionary.AddOrUpdate(key, creator, updater); } V latest = dictionary.TryGetValue(key, out V value) ? updater(key, value) : creator(key); dictionary[key] = latest; return latest; } public static V TryAdd(this IDictionary dictionary, K key, Func creator) { if (dictionary is ConcurrentDictionary concurrentDictionary) { return concurrentDictionary.AddOrUpdate( key, creator, (_, existingValue) => existingValue ); } if (dictionary.TryGetValue(key, out V existing)) { return existing; } V value = creator(key); dictionary[key] = value; return value; } public static Dictionary Merge( this IReadOnlyDictionary lhs, IReadOnlyDictionary rhs ) { Dictionary result = new(); if (0 < lhs.Count) { foreach (KeyValuePair kvp in lhs) { result[kvp.Key] = kvp.Value; } } if (0 < rhs.Count) { foreach (KeyValuePair kvp in rhs) { result[kvp.Key] = kvp.Value; } } return result; } /// /// /// Key type. /// Value type. /// Basis dictionary. /// Changed dictionary. /// All elements of rhs that either don't exist in or are different from lhs public static Dictionary Difference( this IReadOnlyDictionary lhs, IReadOnlyDictionary rhs ) { Dictionary result = new(rhs.Count); foreach (KeyValuePair kvp in rhs) { K key = kvp.Key; if (lhs.TryGetValue(key, out V existing) && Equals(existing, kvp.Value)) { continue; } result[key] = kvp.Value; } return result; } public static Dictionary Reverse(this IReadOnlyDictionary dictionary) { Dictionary output = new(dictionary.Count); foreach (KeyValuePair entry in dictionary) { output[entry.Value] = entry.Key; } return output; } public static Dictionary ToDictionary(this IReadOnlyDictionary dictionary) { return new Dictionary(dictionary); } public static Dictionary ToDictionary( this IReadOnlyDictionary dictionary, IEqualityComparer comparer ) { return new Dictionary(dictionary, comparer); } public static Dictionary ToDictionary( this IEnumerable> prettyMuchADictionary ) { return prettyMuchADictionary.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); } public static Dictionary ToDictionary( this IEnumerable> prettyMuchADictionary, IEqualityComparer comparer ) { return prettyMuchADictionary.ToDictionary(kvp => kvp.Key, kvp => kvp.Value, comparer); } public static Dictionary ToDictionary( this IEnumerable<(K, V)> prettyMuchADictionary ) { return prettyMuchADictionary.ToDictionary(kvp => kvp.Item1, kvp => kvp.Item2); } public static Dictionary ToDictionary( this IEnumerable<(K, V)> prettyMuchADictionary, IEqualityComparer comparer ) { return prettyMuchADictionary.ToDictionary(kvp => kvp.Item1, kvp => kvp.Item2, comparer); } public static bool ContentEquals( this IReadOnlyDictionary dictionary, IReadOnlyDictionary other ) where V : IEquatable { if (ReferenceEquals(dictionary, other)) { return true; } if (ReferenceEquals(dictionary, null) || ReferenceEquals(other, null)) { return false; } return dictionary.Count == other.Count && dictionary.All(kvp => other.TryGetValue(kvp.Key, out V value) && kvp.Value.Equals(value) ); } public static void Deconstruct(this KeyValuePair kvp, out K key, out V value) { key = kvp.Key; value = kvp.Value; } } }