using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using OmegaLeo.HelperLib.Shared.Attributes; namespace OmegaLeo.HelperLib.Models { // Inspiration: https://www.youtube.com/watch?v=x-ejym1WdjE [Serializable] [Documentation("NeoDictionary", "Dictionary like class created to make it easier to display dictionaries in game engines like Unity")] [Changelog("1.2.0", "Fixed root namespace to OmegaLeo.HelperLib.Models.", "January 28, 2026")] public class NeoDictionary { public List> Items = new List>(); public Dictionary ToDictionary() => (Items.Any()) ? Items.ToDictionary(x => x.Key, x => x.Value) : new Dictionary(); public static implicit operator Dictionary(NeoDictionary dict) => (dict.Items.Any()) ? dict.Items.ToDictionary(x => x.Key, x => x.Value) : new Dictionary(); [Documentation("TryGetValue", "Tries to get the value from the NeoDictionary for the given key.")] public bool TryGetValue(TKey key, out TValue value) { var item = Items.FirstOrDefault(x => x.Key.Equals(key)); if (item != null) { value = item.Value; return true; } value = default; return false; } [Documentation("TryGetValueFromIndex", "Tries to get the value from the NeoDictionary at the given index.")] public bool TryGetValueFromIndex(int index, out TValue value) { if (index < Items.Count) { var item = Items[index]; if (item != null) { value = item.Value; return true; } } value = default; return false; } [Documentation("Add", "Adds a new NeoDictionaryItem to the NeoDictionary.")] public void Add(TKey key, TValue value) { Items.Add(new NeoDictionaryItem(key, value)); } [Documentation("AddRange", "Adds a range of NeoDictionaryItems from another NeoDictionary to the NeoDictionary.")] public void AddRange(NeoDictionary values) { Items.AddRange(values.Items); } [Documentation("AddRange", "Adds a range of NeoDictionaryItems to the NeoDictionary.")] public void AddRange(IEnumerable> values) { Items.AddRange(values); } [Documentation("Any", "Checks if the NeoDictionary has any items.")] public bool Any() => Items.Any(); [Documentation("Any", "Checks if any item in the NeoDictionary satisfies a condition.")] public bool Any(Func, bool> predicate) => Items.Any(predicate); [Documentation("Where", "Filters the NeoDictionary items based on a predicate.")] public IEnumerable> Where(Func, bool> predicate) => Items.Where(predicate); [Documentation("FirstOrDefault", "Returns the first item of the NeoDictionary or a default value if the NeoDictionary is empty.")] public NeoDictionaryItem? FirstOrDefault() => Items.FirstOrDefault(); [Documentation("FirstOrDefault", "Returns the first item of the NeoDictionary that satisfies a condition or a default value if no such item is found.")] public NeoDictionaryItem? FirstOrDefault(Func, bool> predicate) => Items.FirstOrDefault(predicate); [Documentation("LastOrDefault", "Returns the last item of the NeoDictionary or a default value if the NeoDictionary is empty.")] public NeoDictionaryItem? LastOrDefault() => Items.LastOrDefault(); [Documentation("LastOrDefault", "Returns the last item of the NeoDictionary that satisfies a condition or a default value if no such item is found.")] public NeoDictionaryItem? LastOrDefault(Func, bool> predicate) => Items.LastOrDefault(predicate); [Documentation("Select", "Projects each item of the NeoDictionary into a new form.")] public IEnumerable> Select(Func, NeoDictionaryItem> selector) => Items.Select(selector); [Documentation("IndexOf", "Returns the index of the given NeoDictionaryItem.")] public int IndexOf(NeoDictionaryItem selector) => Items.IndexOf(selector); [Documentation("Remove", "Removes the item with the given key.")] public void Remove(TKey key) { var index = Items.FindIndex(x => x.Key.Equals(key)); Items.RemoveAt(index); } [Documentation("RemoveAt", "Removes the item at the given index.")] public void RemoveAt(int index) => Items.RemoveAt(index); [Documentation("Replace", "Replaces the value for the given key if it exists.")] public void Replace(TKey key, TValue value) { if (HasKey(key)) { this[key] = value; } } [Documentation("HasKey", "Checks if the NeoDictionary contains the given key.")] public bool HasKey(TKey key) => Items.Any(x => x.Key.Equals(key)); public TValue this[TKey key] { get { if (Items == null) { Items = new List>(); Items.Add(new NeoDictionaryItem(key, (TValue)Activator.CreateInstance(typeof(TValue)))); } try { var value = Items.FirstOrDefault(x => EqualityComparer.Default.Equals(x.Key, key))!.Value; return value ?? (TValue)Activator.CreateInstance(typeof(TValue)); } catch (Exception e) { return (TValue)Activator.CreateInstance(typeof(TValue)); } } set { if (HasKey(key)) { var item = Items.FirstOrDefault(x => EqualityComparer.Default.Equals(x.Key, key)); var index = Items.IndexOf(item); Items[index] = new NeoDictionaryItem(key, value); } else { Items.Add(new NeoDictionaryItem(key, value)); } } } public NeoDictionaryItem this[int index] { get => Items[index]; set => Items[index] = value; } [Documentation("Clear", "Clears all items from the NeoDictionary.")] public void Clear() => Items.Clear(); [Documentation("Sort", "Sorts the NeoDictionary items using the given comparison.")] public void Sort(Comparison> comparison) => Items.Sort(comparison); [Documentation("Count", "Returns the number of items in the NeoDictionary.")] public int Count() => Items.Count; [Documentation("ForEach", "Performs the given action on each item in the NeoDictionary.")] public void ForEach(Action> action) => Items.ForEach(action); [Documentation("ToList", "Converts the NeoDictionary items to a List.")] public List> ToList() => Items.ToList(); [Documentation("Clone", "Creates a shallow copy of the NeoDictionary.")] public NeoDictionary Clone() { var newDict = new NeoDictionary(); newDict.Items = new List>(Items); return newDict; } [Documentation("Reverse", "Reverses the order of the items in the NeoDictionary.")] public void Reverse() => Items.Reverse(); [Documentation("Insert", "Inserts an item at the given index.")] public void Insert(int index, TKey key, TValue value) => Items.Insert(index, new NeoDictionaryItem(key, value)); [Documentation("InsertRange", "Inserts a range of items starting from the given index.")] public void InsertRange(int index, IEnumerable> values) => Items.InsertRange(index, values); [Documentation("RemoveRange", "Removes a range of items starting from the given index.")] public void RemoveRange(int index, int count) => Items.RemoveRange(index, count); [Documentation("RemoveAll", "Removes all items matching the given predicate.")] public void RemoveAll(Func, bool> predicate) => Items.RemoveAll(new Predicate>(predicate)); [Documentation("FindIndex", "Finds the index of the first item matching the given predicate.")] public int FindIndex(Func, bool> predicate) => Items.FindIndex(new Predicate>(predicate)); [Documentation("Find", "Finds the first item matching the given predicate.")] public NeoDictionaryItem Find(Func, bool> predicate) => Items.Find(new Predicate>(predicate)); [Documentation("FindAll", "Finds all items matching the given predicate.")] public IEnumerable> FindAll(Func, bool> predicate) => Items.FindAll(new Predicate>(predicate)); [Documentation("Merge", "Merges another NeoDictionary into this one, ignoring duplicate keys.")] public void Merge(NeoDictionary other) { foreach (var item in other.Items) { if (!HasKey(item.Key)) { Add(item.Key, item.Value); } } } [Documentation("ToDictionarySafe", "Converts the NeoDictionary to a standard Dictionary while safely handling duplicate keys by ignoring them.")] public Dictionary ToDictionarySafe() { var dict = new Dictionary(); foreach (var item in Items) { if (!dict.ContainsKey(item.Key)) { dict.Add(item.Key, item.Value); } } return dict; } } [Serializable] public class NeoDictionaryItem { public TKey Key; public TValue Value; public NeoDictionaryItem(TKey key, TValue value) { Key = key; Value = value; } } }