以前 2 次元配列の要素をインデックス付きで 1 次元配列に落とす、というのを紹介しました。
となると、その逆もやってみたくなりませんか…?*1
拡張メソッドを作る
通常の ToDictionary
メソッドはひとつのプロパティをキーにして辞書を作りますが、このキーをふたつにすればよいでしょう。以下のような感じになります。
//--- キーだけ選択してそのまま要素を格納するバージョン public static Dictionary<TKeyX, Dictionary<TKeyY, TSource>> ToDictionary2<TSource, TKeyX, TKeyY> ( this IEnumerable<TSource> self, Func<TSource, TKeyX> xSelector, Func<TSource, TKeyY> ySelector ) { if (self == null) throw new ArgumentNullException(nameof(self)); if (xSelector == null) throw new ArgumentNullException(nameof(xSelector)); if (ySelector == null) throw new ArgumentNullException(nameof(ySelector)); return self.GroupBy(xSelector) .ToDictionary(x => x.Key, xs => xs.ToDictionary(ySelector)); } //--- キーを選択するだけでなく、要素として何を格納するかを選ぶバージョン public static Dictionary<TKeyX, Dictionary<TKeyY, TElement>> ToDictionary2<TSource, TKeyX, TKeyY, TElement> ( this IEnumerable<TSource> self, Func<TSource, TKeyX> xSelector, Func<TSource, TKeyY> ySelector, Func<TSource, TElement> elementSelector ) { if (self == null) throw new ArgumentNullException(nameof(self)); if (xSelector == null) throw new ArgumentNullException(nameof(xSelector)); if (ySelector == null) throw new ArgumentNullException(nameof(ySelector)); if (elementSelector == null) throw new ArgumentNullException(nameof(elementSelector)); return self.GroupBy(xSelector) .ToDictionary(x => x.Key, xs => xs.ToDictionary(ySelector, elementSelector)); }
使ってみよう
こんなものが一体どんなケースで役に立つというのだ…。と思うかもしれませんが、例えば以下のようなものがあります。
//--- こんなクラスがあるとする class Block { public X { get; set; } public Y { get; set; } public Color Color { get; set; } } //--- こういう 1 次元配列を 2 次元辞書化してしまえば... var blocks = new [] { new Block{ X = 0, Y = 0, Color = Colors.Red }, new Block{ X = 0, Y = 1, Color = Colors.Blue }, new Block{ X = 1, Y = 0, Color = Colors.Green }, new Block{ X = 1, Y = 1, Color = Colors.Yellow }, } .ToDictionary2(x => x.X, x => Y); //--- こんなに分かりやすくなる! var color = blocks[0][1].Color;
…滅多に使わないとは思います(ハイ
*1:普通ならないと思う