Flattening a Dictionary of Lists with LINQ

I am quite fortunate in that being a Freelance Contractor, I can pursue only work that interests me. It is always a bonus when both the work is interesting, and the technology is modern and neat and useful. LINQ is certainly one of these technologies.

In a recent project I got the binary-buzz from the domain (DNA typing) and the technology (LINQ). The requirement was to write some code to manipulate a keyed dictionary of lists (containing in-part an SGM+ DNA profile) and ‘flatten’ it out to a String.

The C# code excerpt below creates a dummy object/test data typical of what I needed to ‘flatten’.


IDictionary<String, IEnumerable> sd = new SortedDictionary<String, IEnumerable>();
sd.Add("FGA", new [] { "16", "28.2" } );
sd.Add("D21", new[] { "25.2", "28.1" });
sd.Add("TH01", new[] { "10", "8.1", "8.3" });
sd.Add("D3", new[] { "12.2", "F"});

I needed to produce a flat String not dissimilar to:


marker: D21 (values: 25.2, 28.1) marker: D3 (values: 12.2, F) marker: FGA (values: 16, 28.2) marker: TH01 (values: 10, 8.1, 8.3)

To solve this type problem, some years ago I would have written an algorithm (and others sadly continue to write this type of code) containing a couple of nested for-loops, a bunch of if/then/else statements, possibly a regex and System.Text.StringBuilder, and with the aid of a debugger and some trial and error, the required String would be painfully built up. This is really unnecessary nowadays, in C# at least. At it’s core, LINQ will come to your rescue, over and over.

Question: Did I achieve this task with LINQ?

Answer: Yes

Question: How did I do it?

Answer: Here you go.


static void Main(string[] args)
{
   IDictionary<String, IEnumerable> sd = new SortedDictionary<String, IEnumerable>();
   sd.Add("FGA", new [] { "16", "28.2" } );
   sd.Add("D21", new[] { "25.2", "28.1" });
   sd.Add("TH01", new[] { "10", "8.1", "8.3" });
   sd.Add("D3", new[] { "12.2", "F"}); //FAIL by Capillary Electrophoresis/Gel

   String s = sd.OrderBy(a => a.Key)
                .Select(a => a.Value.Aggregate($"marker: {a.Key} (values: ", (e1, e2) => $"{e1}{e2}, ").Trim(new char[] { ' ', ',' }))
                .Aggregate("", (o1, o2) => $"{o1}{o2}) ");

   Console.WriteLine(s);
}

In this example, note too I am using interpolated Strings, newly introduced in C#6. For the senior and junior developer alike, you must agree it just doesn’t get any better than this. Believe me!

My Java skills are very dated but nevertheless I had a bash at porting this code to Java. Maybe it can be done, maybe it can’t, but I don’t believe the core language is up to it. If you need to do this type of thing in Java, I suspect it will involve downloading some random library/jar from somewhere introducing an eyebrow-raising dependency, or failing back to writing 1980’s code containing nested for-loops and string concatenation, substring extraction, etc. Oh dear.

— Published by Mike, 21:08:37 08 August 2016

Leave a Reply