From 5ceb60ee9d48f8531f5039e64be57c9b12485610 Mon Sep 17 00:00:00 2001 From: Vladimir Pecanac Date: Wed, 23 Sep 2026 14:33:23 +0200 Subject: [PATCH] Dictionary key by value: retarget net10.0, add prebuilt reverse map benchmarks Both projects move from net8.0 to net10.0. BenchmarkDotNet 0.15.8 and the test packages bumped to today's newest stable. The existing benchmark charges the two reversing methods a full build on every call, which measures a single lookup. ReverseDictionaryLookup builds a reverse Dictionary and a FrozenDictionary once, and two new benchmarks time only the TryGetValue against each, with the maps built in GlobalSetup. The four existing benchmarks are unchanged. Each new method gets the same pair of tests the existing four have. --- .../DictionaryHelperBenchmark.cs | 14 ++++++++ .../GetDictionaryKeyByValue.csproj | 4 +-- .../ReverseDictionaryLookup.cs | 36 +++++++++++++++++++ .../Tests/DictionaryHelperNullTest.cs | 18 ++++++++++ .../Tests/DictionaryHelperPositiveTest.cs | 18 ++++++++++ .../Tests/Tests.csproj | 10 +++--- 6 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 collections-dictionary/GetDictionaryKeyByValue/GetDictionaryKeyByValue/ReverseDictionaryLookup.cs diff --git a/collections-dictionary/GetDictionaryKeyByValue/GetDictionaryKeyByValue/DictionaryHelperBenchmark.cs b/collections-dictionary/GetDictionaryKeyByValue/GetDictionaryKeyByValue/DictionaryHelperBenchmark.cs index fdcc5a0388..d45657f54b 100644 --- a/collections-dictionary/GetDictionaryKeyByValue/GetDictionaryKeyByValue/DictionaryHelperBenchmark.cs +++ b/collections-dictionary/GetDictionaryKeyByValue/GetDictionaryKeyByValue/DictionaryHelperBenchmark.cs @@ -13,6 +13,8 @@ public class DictionaryHelperBenchmark private readonly DictionaryHelper _dictionaryHelper = new(_benchmarkDict, "NonExistentValue"); + private ReverseDictionaryLookup _reverseDictionaryLookup = null!; + private static Dictionary GetDictionary() { var benchmarkDict = new Dictionary(100000); @@ -26,6 +28,10 @@ private static Dictionary GetDictionary() return benchmarkDict; } + [GlobalSetup] + public void Setup() + => _reverseDictionaryLookup = new(_benchmarkDict); + [Benchmark] public string? UseReverseDictionary() => _dictionaryHelper.UseReverseDictionary(); @@ -41,4 +47,12 @@ private static Dictionary GetDictionary() [Benchmark] public string? LoopThroughTheKeys() => _dictionaryHelper.LoopThroughKeys(); + + [Benchmark] + public string? UsePrebuiltReverseDictionary() + => _reverseDictionaryLookup.GetKeyFromReverseDictionary("NonExistentValue"); + + [Benchmark] + public string? UsePrebuiltFrozenDictionary() + => _reverseDictionaryLookup.GetKeyFromFrozenReverseDictionary("NonExistentValue"); } \ No newline at end of file diff --git a/collections-dictionary/GetDictionaryKeyByValue/GetDictionaryKeyByValue/GetDictionaryKeyByValue.csproj b/collections-dictionary/GetDictionaryKeyByValue/GetDictionaryKeyByValue/GetDictionaryKeyByValue.csproj index 848f901f4f..c96a8eb1e7 100644 --- a/collections-dictionary/GetDictionaryKeyByValue/GetDictionaryKeyByValue/GetDictionaryKeyByValue.csproj +++ b/collections-dictionary/GetDictionaryKeyByValue/GetDictionaryKeyByValue/GetDictionaryKeyByValue.csproj @@ -2,13 +2,13 @@ Exe - net8.0 + net10.0 enable enable - + diff --git a/collections-dictionary/GetDictionaryKeyByValue/GetDictionaryKeyByValue/ReverseDictionaryLookup.cs b/collections-dictionary/GetDictionaryKeyByValue/GetDictionaryKeyByValue/ReverseDictionaryLookup.cs new file mode 100644 index 0000000000..a6deaee862 --- /dev/null +++ b/collections-dictionary/GetDictionaryKeyByValue/GetDictionaryKeyByValue/ReverseDictionaryLookup.cs @@ -0,0 +1,36 @@ +using System.Collections.Frozen; + +namespace GetDictionaryKeyByValue; + +public class ReverseDictionaryLookup(Dictionary dict) +{ + private readonly Dictionary _reverseDict = BuildReverseDictionary(dict); + + private readonly FrozenDictionary _frozenReverseDict + = BuildReverseDictionary(dict).ToFrozenDictionary(); + + public string? GetKeyFromReverseDictionary(string value) + { + _reverseDict.TryGetValue(value, out var key); + + return key; + } + + public string? GetKeyFromFrozenReverseDictionary(string value) + { + _frozenReverseDict.TryGetValue(value, out var key); + + return key; + } + + private static Dictionary BuildReverseDictionary(Dictionary dict) + { + var reverseDict = new Dictionary(dict.Count); + foreach (var keyValuePair in dict) + { + reverseDict.TryAdd(keyValuePair.Value, keyValuePair.Key); + } + + return reverseDict; + } +} \ No newline at end of file diff --git a/collections-dictionary/GetDictionaryKeyByValue/Tests/DictionaryHelperNullTest.cs b/collections-dictionary/GetDictionaryKeyByValue/Tests/DictionaryHelperNullTest.cs index a53f20fe04..56103a7823 100644 --- a/collections-dictionary/GetDictionaryKeyByValue/Tests/DictionaryHelperNullTest.cs +++ b/collections-dictionary/GetDictionaryKeyByValue/Tests/DictionaryHelperNullTest.cs @@ -16,6 +16,8 @@ private static readonly Dictionary _dictionary private readonly DictionaryHelper _dictionaryHelper = new(_dictionary, "NonExistentValue"); + private readonly ReverseDictionaryLookup _reverseDictionaryLookup = new(_dictionary); + [Fact] public void GivenANonExistentValue_WhenUseReverseDictionaryIsCalled_ThenReturnsNull() { @@ -47,4 +49,20 @@ public void GivenANonExistentValue_WhenLoopThroughKeysIsCalled_ThenReturnsNull() Assert.Null(result); } + + [Fact] + public void GivenANonExistentValue_WhenGetKeyFromReverseDictionaryIsCalled_ThenReturnsNull() + { + var result = _reverseDictionaryLookup.GetKeyFromReverseDictionary("NonExistentValue"); + + Assert.Null(result); + } + + [Fact] + public void GivenANonExistentValue_WhenGetKeyFromFrozenReverseDictionaryIsCalled_ThenReturnsNull() + { + var result = _reverseDictionaryLookup.GetKeyFromFrozenReverseDictionary("NonExistentValue"); + + Assert.Null(result); + } } \ No newline at end of file diff --git a/collections-dictionary/GetDictionaryKeyByValue/Tests/DictionaryHelperPositiveTest.cs b/collections-dictionary/GetDictionaryKeyByValue/Tests/DictionaryHelperPositiveTest.cs index b1e16c9bbb..813df2d1c9 100644 --- a/collections-dictionary/GetDictionaryKeyByValue/Tests/DictionaryHelperPositiveTest.cs +++ b/collections-dictionary/GetDictionaryKeyByValue/Tests/DictionaryHelperPositiveTest.cs @@ -15,6 +15,8 @@ private static readonly Dictionary _dictionary private readonly DictionaryHelper _dictionaryHelper = new(_dictionary, "value3"); + private readonly ReverseDictionaryLookup _reverseDictionaryLookup = new(_dictionary); + private static readonly string _expectedKey = "key3"; [Fact] @@ -48,4 +50,20 @@ public void GivenAnExistentValue_WhenLoopThroughKeysIsCalled_ThenReturnsTheDesir Assert.Equal(_expectedKey, result); } + + [Fact] + public void GivenAnExistentValue_WhenGetKeyFromReverseDictionaryIsCalled_ThenReturnsTheDesiredKey() + { + var result = _reverseDictionaryLookup.GetKeyFromReverseDictionary("value3"); + + Assert.Equal(_expectedKey, result); + } + + [Fact] + public void GivenAnExistentValue_WhenGetKeyFromFrozenReverseDictionaryIsCalled_ThenReturnsTheDesiredKey() + { + var result = _reverseDictionaryLookup.GetKeyFromFrozenReverseDictionary("value3"); + + Assert.Equal(_expectedKey, result); + } } \ No newline at end of file diff --git a/collections-dictionary/GetDictionaryKeyByValue/Tests/Tests.csproj b/collections-dictionary/GetDictionaryKeyByValue/Tests/Tests.csproj index d3682415b0..f1d190b04c 100644 --- a/collections-dictionary/GetDictionaryKeyByValue/Tests/Tests.csproj +++ b/collections-dictionary/GetDictionaryKeyByValue/Tests/Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable @@ -10,10 +10,10 @@ - - - - + + + +