Dot Net Perls

C# - Convert Dictionary to String

by Sam Allen

Problem

Convert your Dictionary into a string, and read it back from a file and into a new Dictionary. You have a Dictionary of string keys and int values, or other value types. You require an easily readable and logical system of persisting your Dictionary.

Solution: C#

What programmer hasn't had to store key/value pairs on the disk? I faced this challenge on a web project recently. Because this part of the site was important, I wanted precise and total control.

Exact problem. I had to store a Dictionary of string keys and int values. The Dictionary stored frequency values. Dictionary was ideal because it has fast lookup time, so values could be quickly found.

My approach. I have done work with KeyValuePair in Dictionaries. Additionally, my work with StringBuilder and Split was helpful for my approach.

Convert to string

This is also called serialization, and there are advanced methods in .NET you can use. However, if you want exact control, my method may be best.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

class ConvertDictionary
{
    Dictionary<string, int> _dictionary = new Dictionary<string, int>()
    {
        {"salmon", 5},
        {"tuna", 6},
        {"clam", 2},
        {"asparagus", 3}
    };

    public ConvertDictionary()
    {
        //
        // Convert dictionary to string and save
        //
        string s = GetLine(_dictionary);
        File.WriteAllText("dict.txt", s);
        //
        // Get dictionary from that file
        //
        Dictionary<string, int> d = GetDict("dict.txt");
    }

    string GetLine(Dictionary<string, int> d)
    {
        //
        // Build up each line one-by-one and them trim the end
        //
        StringBuilder builder = new StringBuilder();
        foreach (KeyValuePair<string, int> pair in d)
        {
            builder.Append(pair.Key).Append(":").Append(pair.Value).Append(',');
        }
        string result = builder.ToString();
        //
        // Remove the final delimiter
        //
        result = result.TrimEnd(',');
        return result;
    }

    Dictionary<string, int> GetDict(string f)
    {
        Dictionary<string, int> d = new Dictionary<string, int>();
        string s = File.ReadAllText(f);
        //
        // Divide all pairs (remove empty strings)
        //
        string[] tokens = s.Split(new char[] { ':', ',' },
            StringSplitOptions.RemoveEmptyEntries);
        //
        // Walk through each item
        //
        for (int i = 0; i < tokens.Length; i += 2)
        {
            string name = tokens[i];
            string freq = tokens[i + 1];

            //
            // Parse the int (this can throw)
            //
            int count = int.Parse(freq);
            //
            // Fill the value in the sorted dictionary
            //
            if (d.ContainsKey(name))
            {
                d[name] += count;
            }
            else
            {
                d.Add(name, count);
            }
        }
        return d;
    }
}

A. GetLine()

In the above code sample, you receive a string from the Dictionary<string, int>. It is up to you to write this to the file.

The dictionary used. In the above example, GetLine receives a Dictionary that was declared at the class-level. It uses the syntax for declaration.

How GetLine works. It declares a new StringBuilder, which helps performance here. Next, it iterates through the Dictionary's KeyValuePair collection.

StringBuilder usage. The Append calls are chained, which also improves performance. Semicolons separate the two parts of each pair, and commas separate the pairs. Here's the final string:

B. GetDict()

Now we must get a new Dictionary<string, int> from the file we saved it to. GetDict here does that for us. First, it declares the Dictionary it will return. It reads in the specified file with .NET file handling.

Splits on multiple chars. The string has both commas and semicolons that separate parts. We split on both characters and then consume the results two at a time. Here's what Visual Studio's debugger will show.

Dictionary lookups. We use ContainsKey and Add on the Dictionary we are building up. This is efficient and works reliably.

This code will crash!

... but that's not my fault. Whenever you deal with the file system, your input may become corrupted. It will fail. So deal with as best you can with exceptions. The two calls above should be wrapped in exceptions.

try
{
    //
    // Convert dictionary to string and save
    //
    string s = GetLine(_dictionary);
    File.WriteAllText("dict.txt", s);
}
catch
{
    //
    // A.
    // Recover if we can.
    //
}

try
{
    //
    // Get dictionary from that file
    //
    Dictionary<string, int> d = GetDict("dict.txt");
}
catch
{
    //
    // B.
    // If this is critical, rethrow.
    //
}

Some exception stuff. Whenever you deal with the file system and your code is not critical, try to recover from any errors. Recover by returning an error string, blank string, or just doing nothing. Log it.

You're a genius!

Thanks, but there are many other ways to serialize data and dictionaries, and this is not necessarily the best. It is reliable and gives you precise control. It could be easily changed to store string pairs.

Summary

Write your Dictionary to disk and read it back in again. Develop custom methods to do this with the best performance. This method is easily extended to other languages such as Python. Be on the lookout for exceptions and other bad behavior.

 
© 2008 Sam Allen. All rights reserved.

Ads by The Lounge