I tried another approach that works great for smaller dictionaries.
The idea is to just iterate the dictionary from start until everything is removed. Because the enumerator is a struct, it is allocation free in .NET Core. Of course this method should not be used for large dictionaries.
while (true)
{
var isRemoved = false;
foreach (var kvp in dict)
{
if (kvp.Key == "15" || kvp.Key == "20")
{
source.Remove(kvp.Key);
isRemoved = true;
break;
}
}
if (!isRemoved)
{
break;
}
}
I tested a few alternatives:
[SimpleJob]
[MemoryDiagnoser]
public class DictionaryRemove
{
private Dictionary<string, string> source;
[IterationSetup]
public void Setuo()
{
source = new Dictionary<string, string>();
for (var i = 0; i < 20; i++)
{
source.Add($"{i}", $"{i}");
}
}
[Benchmark]
public void Remove_Linq_Keys()
{
foreach (var key in source.Keys.Where(x => x == "15" || x == "20").ToList())
{
source.Remove(key);
}
}
[Benchmark]
public void Remove_Linq_Normal()
{
foreach (var kvp in source.Where(x => x.Key == "15" || x.Key == "20").ToList())
{
source.Remove(kvp.Value);
}
}
[Benchmark]
public void Remove_Plain()
{
while (true)
{
var isRemoved = false;
foreach (var kvp in source)
{
if (kvp.Key == "15" || kvp.Key == "20")
{
source.Remove(kvp.Key);
isRemoved = true;
break;
}
}
if (!isRemoved)
{
break;
}
}
}
}
And the results
| Method | Mean | Error | StdDev | Median | Allocated |
|------------------- |----------:|----------:|----------:|----------:|----------:|
| Remove_Linq_Keys | 16.680 us | 1.2932 us | 3.7519 us | 16.200 us | 688 B |
| Remove_Linq_Normal | 6.755 us | 0.4254 us | 1.1928 us | 6.200 us | 720 B |
| Remove_Plain | 1.936 us | 0.1540 us | 0.4319 us | 1.800 us | 480 B |
If you know that your dictionary is relatively small, it might be a good alternative.