如何更新字典中键的值,但前提是该键已经存在,而不需要对键进行两次哈希处理?

2023-11-26

我有一个Dictionary<string, decimal>具有固定数量的条目,并且我想经常更新它的许多值,但仅限于已经存在的键。如果字典中尚不存在某个键,我不想添加它,因为我的目标是将字典限制为固定大小。所以下面的代码(使用set indexer)无法满足我的需求:

dictionary[key] = newValue;

此代码将更新key如果它已经存在,或者如果不存在,它将插入一个新的键/值对。那不是我想要的。所以我写了一个扩展方法TryUpdate为了Dictionary<TKey, TValue>类,具有理想的行为:

public static bool TryUpdate<TKey, TValue>(
    this Dictionary<TKey, TValue> source,
    TKey key, TValue value)
{
    ArgumentNullException.ThrowIfNull(source);
    if (!source.ContainsKey(key))
        return false;
    source[key] = value;
    return true;
}

现在我的代码按预期工作:

dictionary.TryUpdate(key, newValue);

我不喜欢上述实现的是,如果密钥已经存在,这是我的场景中的常见情况,则密钥将在每个密钥中被哈希两次TryUpdate手术。因此,为了保证我的字典不会增长超过其初始大小,我将在性能方面付出双倍的代价。键是长字符串,因此哈希成本很高。有什么办法重写我的TryUpdate方法,因此它的性能与set索引器?


从 .NET 6 开始,无需使用包装器 - 使用CollectionsMarshal.GetValueRefOrNullRef反而:

获取对 a 的引用TValue in the Dictionary<TKey, TValue>或参考null如果字典中不存在。

var x = new Dictionary<string, string>{{"test", "1"}};
ref var valueRefOrNullRef = ref CollectionsMarshal.GetValueRefOrNullRef(x, "test");
if (!Unsafe.IsNullRef(ref valueRefOrNullRef))
{
    valueRefOrNullRef = "2";
}

Console.WriteLine(x["test"]); // prints 2

UPD

全面实施:

public static bool TryUpdate<TKey, TValue>(
    this Dictionary<TKey, TValue> source,
    TKey key,
    TValue value)
    where TKey : notnull
{
    ArgumentNullException.ThrowIfNull(source);
    ref var valueRefOrNullRef = ref CollectionsMarshal.GetValueRefOrNullRef(source, key);
    if (Unsafe.IsNullRef(ref valueRefOrNullRef))
    {
        return false;
    }

    valueRefOrNullRef = value;
    return true;
}

var x = new Dictionary<string, decimal> { { "test", 1 } };
Console.WriteLine(x.TryUpdate("test", 2)); // True
Console.WriteLine(x.TryUpdate("test1", 2)); // False
Console.WriteLine(x["test"]); // 2
Console.WriteLine(x.ContainsKey("test2")); // False

请注意,此方法有以下限制(与包装器相比):

不应添加或删除项目Dictionary<TKey, TValue>ref TValue正在使用中。

UPD2

只是为了搞笑创造了一个小基准(当然并不理想,它至少严重错过了字符串和字典大小差异)但似乎即使对于小字典和小/中字符串长度,通过键进行单次访问的方法也更快:

Method Mean Error StdDev
BothUsingCollectionsMarshal 204.92 ns 2.008 ns 1.677 ns
BothUsingDoubleAccess 355.74 ns 5.947 ns 6.107 ns
OnlyPresentUsingCollectionsMarshal 116.19 ns 2.225 ns 2.081 ns
OnlyPresentUsingDoubleAccess 271.66 ns 5.423 ns 5.326 ns
OnlyMissingUsingCollectionsMarshal 91.20 ns 1.851 ns 1.818 ns
OnlyMissingUsingDoubleAccess 94.78 ns 1.891 ns 2.524 ns
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何更新字典中键的值,但前提是该键已经存在,而不需要对键进行两次哈希处理? 的相关文章

随机推荐