Dictionary & Collection Helpers
Garyon provides powerful extensions and helpers for dictionaries, collections, lists, and other data structures, making common operations more convenient and efficient.
Dictionary Extensions
IncrementOrAddKeyValue
Increment a counter in a dictionary, adding the key if it doesn't exist:
using Garyon.Extensions;
var wordCount = new Dictionary<string, int>();
wordCount.IncrementOrAddKeyValue("hello");
wordCount.IncrementOrAddKeyValue("world");
wordCount.IncrementOrAddKeyValue("hello");
// wordCount: { "hello": 2, "world": 1 }
ValueOrDefault
Get a value or return a default if the key doesn't exist:
using Garyon.Extensions;
var config = new Dictionary<string, string>
{
["host"] = "localhost",
["port"] = "8080"
};
string host = config.ValueOrDefault("host"); // "localhost"
string timeout = config.ValueOrDefault("timeout"); // null
string maxRetries = config.ValueOrDefault("retries", "3"); // "3" (default)
AddRange
Add multiple key-value pairs at once:
using Garyon.Extensions;
var dict = new Dictionary<string, int>();
var newEntries = new Dictionary<string, int>
{
["one"] = 1,
["two"] = 2,
["three"] = 3
};
dict.AddRange(newEntries);
List Extensions
Swap Elements
using Garyon.Extensions;
var list = new List<string> { "A", "B", "C", "D" };
list.Swap(0, 2);
// list: ["C", "B", "A", "D"]
list.Swap(^1, ^2);
// list: ["C", "B", "D", "A"]
Collection Extensions
IsEmpty / IsNotEmpty
using Garyon.Extensions;
var numbers = new List<int>();
if (numbers.IsEmpty())
{
Console.WriteLine("No numbers");
}
numbers.Add(42);
if (numbers.IsNotEmpty())
{
Console.WriteLine($"Has {numbers.Count} numbers");
}
AddIfNotNull
using Garyon.Extensions;
var items = new List<string>();
string value1 = "hello";
string value2 = null;
items.AddIfNotNull(value1); // Added
items.AddIfNotNull(value2); // Not added
// items: ["hello"]
Cloning
Clone collections efficiently:
using Garyon.Extensions;
var original = new List<int> { 1, 2, 3 };
var clone = original.CloneList();
clone.Add(4);
// original: [1, 2, 3]
// clone: [1, 2, 3, 4]
Specialized Collections
FlexDictionary
A dictionary that creates values on first access:
using Garyon.DataStructures;
// Auto-create lists when accessing new keys
var groups = new FlexDictionary<string, List<int>>(() => new List<int>(20));
groups["evens"].Add(2);
groups["evens"].Add(4);
groups["odds"].Add(1);
groups["odds"].Add(3);
// No need to check ContainsKey or initialize lists manually
FlexInitDictionary
A dictionary that creates values on first access, using the parameterless constructor if available:
using Garyon.DataStructures;
// Auto-create lists when accessing new keys
var groups = new FlexInitDictionary<string, List<int>>();
groups["evens"].Add(2);
groups["evens"].Add(4);
groups["odds"].Add(1);
groups["odds"].Add(3);
// No need to check ContainsKey or initialize lists manually
ValueCounterDictionary
Automatically count occurrences:
using Garyon.Objects;
var counter = new ValueCounterDictionary<string>();
counter.Add("apple");
counter.Add("banana");
counter.Add("apple");
counter.Add("apple");
int appleCount = counter["apple"]; // 3
int bananaCount = counter["banana"]; // 1
InterlinkedDictionary
Bidirectional key-value mapping:
using Garyon.DataStructures;
var interlinked = new InterlinkedDictionary<int, string>();
interlinked.Add(1, "one");
interlinked.Add(2, "two");
string value = interlinked[1]; // "one"
int key = interlinked.GetKey("two"); // 2
// Both directions maintained automatically
ConcurrentSet
Thread-safe set implementation:
using Garyon.DataStructures;
using System.Threading.Tasks;
var set = new ConcurrentSet<int>();
Parallel.For(0, 1000, i =>
{
set.Add(i % 100); // Thread-safe
});
int uniqueCount = set.Count; // Will be 100
Queue and Stack Extensions
Queue Extensions
using Garyon.Extensions;
var queue = new Queue<int>();
queue.EnqueueRange(new[] { 1, 2, 3, 4, 5 });
// Dequeue multiple
var items = queue.DequeueRange(3); // [1, 2, 3]
Stack Extensions
using Garyon.Extensions;
var stack = new Stack<string>();
stack.PushRange(new[] { "A", "B", "C" });
// Pop multiple
var items = stack.PopRange(2); // ["C", "B"]
StackSet and QueueSet
Sets with stack/queue ordering:
using Garyon.DataStructures;
// Stack with unique elements
var stackSet = new StackSet<int>();
stackSet.Push(1);
stackSet.Push(2);
stackSet.Push(1); // Ignored, already exists
// Queue with unique elements
var queueSet = new QueueSet<int>();
queueSet.Enqueue(1);
queueSet.Enqueue(2);
queueSet.Enqueue(1); // Ignored
Examples
Word Frequency Counter
using Garyon.Extensions;
using System.Text.RegularExpressions;
public class WordFrequency
{
public static ValueCounterDictionary<string> CountWords(string text)
{
var frequency = new ValueCounterDictionary<string>();
var words = Regex.Split(text.ToLower(), @"\W+")
.Where(w => !string.IsNullOrWhiteSpace(w));
foreach (var word in words)
{
frequency.Add(word);
}
return frequency;
}
public static void PrintTopWords(string text, int top = 10)
{
var frequency = CountWords(text);
var topWords = frequency
.OrderByDescending(kvp => kvp.Value)
.Take(top);
foreach (var (word, count) in topWords)
{
Console.WriteLine($"{word}: {count}");
}
}
}
Grouping Helper
using Garyon.Extensions;
using Garyon.DataStructures;
public class DataGrouper<T>
{
private readonly FlexDictionary<string, List<T>> _groups;
public DataGrouper()
{
_groups = new FlexDictionary<string, List<T>>(() => new List<T>());
}
public void Add(string group, T item)
{
_groups[group].Add(item); // Auto-creates list if needed
}
public void AddRange(string group, IEnumerable<T> items)
{
_groups[group].AddRange(items);
}
public List<T> GetGroup(string group)
{
return _groups.ValueOrDefault(group) ?? new List<T>();
}
public Dictionary<string, int> GetGroupSizes()
{
return _groups.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value.Count
);
}
}
Performance Tips
- Pre-size collections: Use capacity constructors when size is known
- Use appropriate collection: Choose based on access patterns
- Avoid repeated lookups: Cache dictionary lookups
- Batch operations: Use AddRange instead of multiple Add calls
- Consider concurrent collections: For multi-threaded scenarios
Efficient Dictionary Usage
// ❌ Multiple lookups
if (dict.ContainsKey(key))
{
var value = dict[key];
Process(value);
}
// ✅ Single lookup
if (dict.TryGetValue(key, out var value))
{
Process(value);
}
// ✅ With Garyon extension
var value = dict.ValueOrDefault(key);
if (value != null)
{
Process(value);
}
Best Practices
- Use IncrementOrAddKeyValue: For counting scenarios
- ValueOrDefault: Safer than direct indexing
- Null checks: Use AddIfNotNull for safety
- Thread safety: Use ConcurrentSet/ConcurrentDictionary for parallel access
- Specialized collections: Use FlexDictionary, ValueCounterDictionary for specific patterns
API Reference
See the following API references: