LoginSignup
11
9

More than 5 years have passed since last update.

ToDictionaryメソッドで「キーが重複した」エラーが出た時の対策について

Last updated at Posted at 2018-02-08

問題説明

LINQにおけるToDictionaryメソッドでは、キーが重複するとArgumentExceptionが発生します

sample1.cs
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    using Idol = KeyValuePair<string, int>;
    class Program
    {
        static void Main(string[] args) {
            // サンプルデータ
            var list = new [] {
                new Idol("島村卯月", 17),
                new Idol("櫻井桃華", 12),
                new Idol("相原雪乃", 22),
                new Idol("安部菜々", 17),   //ウーサミン!
            };
            //  例外がスローされました: 'System.ArgumentException' (mscorlib.dll の中)
            //  型 'System.ArgumentException' のハンドルされていない例外が mscorlib.dll で発生しました
            //  同一のキーを含む項目が既に追加されています。
            var dic = list.ToDictionary(idol => idol.Value, idol => idol.Key);
        }
    }
}

 つまり、全部LINQで片付けようとすると、「事前にキーが重複しないか調べる」という面倒な手間が発生するわけです。
 もちろん次のように書けば問題ありませんが、やはり冗長に見えますよね?

sample2.cs
using System.Collections.Generic;

namespace ConsoleApp1
{
    using Idol = KeyValuePair<string, int>;
    class Program
    {
        static void Main(string[] args) {
            // サンプルデータ
            var list = new [] {
                new Idol("島村卯月", 17),
                new Idol("櫻井桃華", 12),
                new Idol("相原雪乃", 22),
                new Idol("安部菜々", 17),   //ウーサミン!
            };
            // 無難な追加方法
            // dicの中身はKeyValuePair<int, string>型で
            // [0] {[17, 安部菜々]}
            // [1] {[12, 櫻井桃華]}
            // [2] {[22, 相原雪乃]}
            var dic = new Dictionary<int, string>();
            foreach(var idol in list) {
                dic[idol.Value] = idol.Key;
            }
        }
    }
}

解決策

 GroupByメソッドを使えば良いのでした。これでキー毎にグルーピングした後、それぞれについてLastメソッドを使えば、上記のsample2.csと同じ結果が返ってきます。

sample3.cs
using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    using Idol = KeyValuePair<string, int>;
    class Program
    {
        static void Main(string[] args) {
            // サンプルデータ
            var list = new [] {
                new Idol("島村卯月", 17),
                new Idol("櫻井桃華", 12),
                new Idol("相原雪乃", 22),
                new Idol("安部菜々", 17),   //ウーサミン!
            };
            // あくまでLINQによる解決策
            // dicの中身はKeyValuePair<int, string>型で
            // [0] {[17, 安部菜々]}
            // [1] {[12, 櫻井桃華]}
            // [2] {[22, 相原雪乃]}
            var dic = list.GroupBy(idol => idol.Value)
                .ToDictionary(idolGroup => idolGroup.Last(), idolGroup => idolGroup.Key);
        }
    }
}
11
9
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
9