Home > front end >  Storing and accessing complexed Key of dictionary - in nested dict or delimited key? C#
Storing and accessing complexed Key of dictionary - in nested dict or delimited key? C#

Time:11-25

I wonder what is better from performance side? I have big data that I work with. Sometimes Dict inside dict inside dict ...... Initializing that nested dict is more complicated. I prefer to store the keys by a delimited char:

key = key1|key2|...|key3

When I need to access a specific "key" I just split the key and searching for the specific keys. What is better?

CodePudding user response:

Every time you are concatenating strings to use as a unified key, you are creating garbage for the garbage collector. This has a performance impact that is not trivial to measure, because you dοn't pay the price instantly. You are paying it when the garbage collection kicks in, and has more work to do than usual. Concatenating strings is also not a bullet proof approach, because it is based on the assumption that the delimiter (the pipe character in your example), is never contained in any of the subkeys. I would say that making this kind of assumptions is a characteristic feature of amateur programming. Professionals hate to base the correctness of their programs on conditions that are not under their complete control.

My suggestion is to use value tuples as keys. For example in case each key is composed of 3 string parts, you could declare your dictionary like this:

Dictionary<(string, string, string), MyItem> dictionary = new();
//...
dictionary.Add(("key1", "key2", "key3"), new MyItem());
//...
if (dictionary.TryGetValue(("key1", "key2", "key3"), out var item)) //...

This will search for the keys with case sensitivity. In case you prefer your searches to be case insensitive, you could create a custom comparer that implements the IEqualityComparer<(string, string, string)> interface, implement accordingly the Equals and GetHashCode methods (look here for an example), and pass an instance to the constructor of the dictionary. You'll probably have to use the StringComparer.OrdinalIgnoreCase in the implementation.

Another option is to install the Nito.Comparers package, and create your comparer fluently like this:

var myComparer = Nito.Comparers.EqualityComparerBuilder
    .For<(string, string, string)>()
    .EquateBy(x => x.Item1, StringComparer.OrdinalIgnoreCase)
    .ThenEquateBy(x => x.Item2, StringComparer.OrdinalIgnoreCase)
    .ThenEquateBy(x => x.Item3, StringComparer.OrdinalIgnoreCase);
  • Related