如何仅使用单个键查找来改变字典条目?

时间:2013-04-05 13:01:17

标签: c# dictionary

假设我需要增加Value中条目的Dictionary,例如:

public void Increment( string key, int increment )
{
    m_dict[key] += increment;
}

并假设我需要在key没有条目时使其工作,例如:

public void Increment( string key, int increment )
{
    if ( m_dict.ContainsKey( key ) )
    {
        m_dict[key] += increment;
    }
    else
    {
        m_dict[key] = increment;
    }
}

有没有办法将key次查找次数减少到一次?

我能想到的最佳解决方案如下,有点笨重并使用两个查找:

public void Increment( string key, int increment )
{
    long value;
    if ( m_dict.TryGetValue( key, out value ) )
    {
        m_dict[key] = value + increment;
    }
    else
    {
        m_dict.Add( key, increment );
    }
}

2 个答案:

答案 0 :(得分:1)

我不确定它是否只进行了一次查找,但ConcurrentDictionary有一个AddOrUpdate方法,它具有您正在寻找的行为,但正如我所说,我可以不确定查找次数。

请参阅:http://msdn.microsoft.com/en-gb/library/ee378675.aspx

此外,我相信Dictionary具有自动AddOrUpdate行为:

_dict["key"] = 12将始终变异或添加,具体取决于它是否已存在。

答案 1 :(得分:1)

你可以使用类似的东西。

public class Holder {
    public long Value { get; set; }
}

public void Increment(Dictionary<string, Holder> dict, string key, int increment) {
        Holder box;
        if(dict.TryGetValue(key, out box)) box.Value += increment;
        else {
            dict[key] = new Holder {
                Value = increment
            };
        }
    }

包装类对性能没有明显的影响,因为这几乎等于已经发生的boxin / unboxing(我认为)。

我做了一个小测试,性能似乎更好,你必须确认所有用例中的性能是否更好。

  [Fact]
        public void benchmark_dictionary() {
            var dictionary = new Dictionary<string, long> {
                {"a", 1},
                {"b", 2},
                {"c", 3}
            };

            var dictionary2 = new Dictionary<string, Holder> {
                {
                    "a", new Holder() {
                        Value = 1
                    }
                }, {
                    "b", new Holder() {
                        Value = 2
                    }
                }, {
                    "c", new Holder() {
                        Value = 3
                    }
                }
            };

            var iterations = 1000000;
            var timer = new Stopwatch();
            timer.Start();
            for(int i = 0; i < iterations; i++)
                Increment(dictionary, "a", 1);
            timer.Stop();

            // DumpOnConsole() -> Console.WriteLine( objetc ) 
            timer.ElapsedMilliseconds.DumpOnConsole();

            dictionary.DumpOnConsole();

            timer.Restart();

            for(int i = 0; i < iterations; i++)
                Increment(dictionary2, "a", 1);
            timer.Stop();

            timer.ElapsedMilliseconds.DumpOnConsole();

            dictionary2.DumpOnConsole();
        }

的问候。