0

假设我需要增加Valuea 中的条目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 );
    }
}
4

2 回答 2

1

I'm not certain whether it only does the one lookup under the hood, but ConcurrentDictionary has an AddOrUpdate method that has the behaviour you're looking for, but as I said, I can't be sure of the number of lookups.

See: http://msdn.microsoft.com/en-gb/library/ee378675.aspx

Furthermore, I believe Dictionary has the automatic AddOrUpdate behaviour:

_dict["key"] = 12 will always mutate or add depending on whether it exists already.

于 2013-04-05T13:07:43.263 回答
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
            };
        }
    }

包装类不会对性能产生明显影响,因为这几乎等于已经发生的装箱/拆箱(我认为)。

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

  [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();
        }

问候。

于 2013-04-05T13:39:22.443 回答