Home > Enterprise >  Efficient use of char[] or string as dictionary value
Efficient use of char[] or string as dictionary value

Time:01-04

From the resources point what will be more efficient use string or char array as dictionary value? I'm assuming that using char[] is more efficient than using a string, but I haven't found any confirmation of this assumption.

        private readonly ImmutableDictionary<char, char[]> map = new Dictionary<char, char[]>
        {
            { 'x',  new[] { 'a' } },
            { 'y',  new[] { 'd', 'e' } },
            { 'z',  new[] { 'g', 'h', 'i' } },
           
            /// hundreds of other key-value pairs
        }.ToImmutableDictionary();

        public StringBuilder Convert(char[] text)
        {           
            StringBuilder sb = new();

            foreach (char c in text)
            {
                if (map.TryGetValue(c, out char[] val))
                    sb.Append(val);
                else
                    sb.Append(c);
            }
            return sb;
        }

OR

        private readonly ImmutableDictionary<char, string> map = new Dictionary<char, string>
        {
            { 'x', "a" },
            { 'y', "de" },
            { 'z', "ghi" },

            /// hundreds of other key-value pairs
        }.ToImmutableDictionary();
        
        public StringBuilder Convert(char[] text)
        {           
            StringBuilder sb = new();

            foreach (char c in text)
            {
                if (map.TryGetValue(c, out string val))
                    sb.Append(val);
                else
                    sb.Append(c);
            }
            return sb;
        }
        
        

CodePudding user response:

While I question the use of an ImmutableDictionary unless you absolutely need one, it is possible to benchmark the differences between the two value options for both the construction and access of the entries.

With the following trivialized creation benchmark:

[MemoryDiagnoser]
[ShortRunJob]
public class DictionaryBenchmarks
{
    [Benchmark(Baseline = true)]
    public IDictionary<char, char[]> CharArrayValueBenchmark()
    {
        return new Dictionary<char, char[]>
        {
            { 'x',  new[] { 'a' } },
            { 'y',  new[] { 'd', 'e' } },
            { 'z',  new[] { 'g', 'h', 'i' } },
           
            /// hundreds of other key-value pairs
        }.ToImmutableDictionary();
    }

    [Benchmark]
    public IDictionary<char, string> StringValueBenchmark()
    {
        return new Dictionary<char, string>
        {
            { 'x', "a" },
            { 'y', "de" },
            { 'z', "ghi" }
           
            /// hundreds of other key-value pairs
        }.ToImmutableDictionary();
    }
}

I get the following results:

CreationBenchmark

where the cost to create string entries is lower. This makes sense, since there is no need for the containing array per value. As a result, less memory is used and the execution time is faster.

On the flip side, when accessing those entries:

[MemoryDiagnoser]
[ShortRunJob]
public class DictionaryBenchmarks
{
    private readonly ImmutableDictionary<char, char[]> charArrayValueMap = new Dictionary<char, char[]>
    {
        { 'x',  new[] { 'a' } },
        { 'y',  new[] { 'd', 'e' } },
        { 'z',  new[] { 'g', 'h', 'i' } },
           
        /// hundreds of other key-value pairs
    }.ToImmutableDictionary();


    private readonly ImmutableDictionary<char, string> stringValueMap = new Dictionary<char, string>
    {
        { 'x', "a" },
        { 'y', "de" },
        { 'z', "ghi" },

        /// hundreds of other key-value pairs
    }.ToImmutableDictionary();

    [Benchmark(Baseline = true)]
    public char[] CharArrayValueBenchmark()
    {
        return charArrayValueMap['y'];
    }

    [Benchmark]
    public string StringValueBenchmark()
    {
        return stringValueMap['y'];
    }
}

lookupBenchmark

it is possible that there is a slight advantage to the string value dictionary, although I'm inclined to dismiss it as variance that should disappear over more iterations.

While this does not respect your potential use case of hundreds of entries, I see no reason why you would use a char array value dictionary, unless that made more sense for your use case, since it will require more memory to create the instance.

Finally, a regular dictionary will outperform ImmutableDictionary and is absolutely the better choice for performance-sensitive paths, as long as you are willing to entertain the possibility of a developer trying to update it, which in turn would require locking to ensure thread-safety.

  • Related