There are many times where I need to convert an array of data into a Dictionary or Hash table. If the key to be used in the new Dictionary is not unique, it is necessary to manage duplicates. I previously went through a lot of gyrations, but eventually setteled on the ILookup. ILookup is not perfect, but it beats some alternatives.
Note this example (given the following structure):
public static List<string[]> lst_arr_strData = new List<string[]>()
{
new string[] {"fred", "1"},
new string[] {"joe", "1"},
new string[] {"bill", "1"},
new string[] {"sam", "1"},
new string[] {"dave", "1"},
new string[] {"fred", "2"},
new string[] {"joe", "2"}
};
Technique 0: Throw an Exception : Argument Exception : Message="An item with the same key has already been added."


Technique 1: Ignore/discard duplicates

Technique 2: Add the duplicate data as an Enumerable type
Example: Dictionary<TKey, List<TValue>>
.jpg)
ToLookup converts an IEnumerable<T> to a Lookup<Key, Element> type. Lookup is like a dictionary, but where a Dictionary uses a single key value, Lookup maps the keys to a collection of values. Lookups have no public constructor and are immutable. You cannot add or remove elements or keys after they are created.
Technique 3: Convert the data using the Enumerable.ToLookup
ILookup<TKey, TElement>
http://msdn.microsoft.com/en-us/library/bb549073.aspx
In this example, I show the calling code and the ILookup solution in C++, C# and VB
////////////////////////////////////////////////////////////////////////////////
// CSharp Main program
using System;
using System.Collections.Generic;
using System.Linq;
using LinqTestCPP;
using LinqTestCS;
using LinqTestVB;
//
namespace LinqTestShell
{
class LinqTest
{
//////////////////////////////////////////////////////////////////////////
// here is some static data to convert to the ILookup
public static List<string[]> lst_arr_strData = new List<string[]>()
{
new string[] {"fred", "1"},
new string[] {"joe", "1"},
new string[] {"bill", "1"},
new string[] {"sam", "1"},
new string[] {"dave", "1"},
new string[] {"fred", "2"},
new string[] {"joe", "2"}
};
static void Main(string[] args)
{
// Interfaces will/should look exactly the same.
Console.WriteLine("--- C++ ---");
CLinqTestCPP.LinqTest(lst_arr_strData);
Console.WriteLine("--- CSharp ---");
CLinqTestCS.LinqTest(lst_arr_strData);
Console.WriteLine("--- VB ---");
CLinqTestVB.LinqTest(lst_arr_strData);
}
}
}
C++ Example:
// CPP implementation
#pragma once
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Linq;
namespace LinqTestCPP {
public ref class CLinqTestCPP
{
protected:
//
static String^ GetFirst(array<String^>^ arr){
return Enumerable::First<String^>(arr);
}
public:
//
static void LinqTest(List<array<String^>^>^ lst_arr_strData)
{
ILookup<String^, array<String^>^>^ lkup =
Enumerable::ToLookup(lst_arr_strData,
gcnew Func<array<String^>^, String^>(GetFirst)
);
for each (IGrouping<String^, array<String^>^>^ arr in lkup)
{
Console::Write(arr->Key);
for each (array<String^>^ s in arr)
{
Console::Write("\t" + s[1]);
}
Console::WriteLine();
}
}
};
}
C# (CSharp) Example:
////////////////////////////////////////////////////////////////////////////////
// CSharp implementation
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqTestCS
{
public class CLinqTestCS
{
public static void LinqTest(List<string[]> lst_arr_strData)
{
// (using Extension)
/* ILookup<string, string[]> lkup =
lst_arr_strData.ToLookup(key => key.First()); */
ILookup<string, string[]> lkup =
Enumerable.ToLookup(lst_arr_strData,
new Func<string[], String>(Enumerable.First)
);
foreach (IGrouping<string, string[]> arr in lkup)
{
Console.Write(arr.Key);
foreach (var s in arr)
{
Console.Write("\t" + s[1]);
}
Console.WriteLine();
}
}
}
}
VB Example:
' //////////////////////////////////////////////////////////////////////////////
' // VB Implementation
Imports System.Linq
Public Class CLinqTestVB
Public Shared Sub LinqTest(ByVal lst_arr_strData As List(Of String()))
' (using Extension)
' Dim lkup As ILookup(Of String, String()) = _
' lst_arr_strData.ToLookup(Function(key) key.First())
Dim lkup As ILookup(Of String, String()) = _
Enumerable.ToLookup(lst_arr_strData, _
New Func(Of String(), String)(AddressOf Enumerable.First))
For Each arr As IGrouping(Of String, String()) In lkup
Console.Write(arr.Key)
For Each s As String() In arr
Console.Write(Chr(9) + s(1))
Next
Console.WriteLine()
Next
End Sub
End Class
:and the output...:
