概要
業務にて、タイトルの通りカスタムクラスとLINQを組み合わせたDictionaryを使った実装が必要になったため、勉強と記録がてら記事作成します。
やりたいこと
ざっくり、以下のような感じです。
(実際は全然違う内容ですが、便宜上置き換えています)
社員がノートに1行ずつ起票をしていく運用のノートがある。
ノートでは、同じ社員が複数行起票することがある。
このノートにおいて、各社員が何行目に起票したかを整理し、表示する。
上記において、 社員情報-記入した行のリスト という形のDictionayを使用することで対応しました。
ポイント
Dictionaryにおいて、Keyを同一とみなすためには以下を満たす必要があるようです。
GetHashCodeの結果が同じであること
Equalsの結果がtrueであること
したがって、Keyに独自のクラスを使用する場合は、上記2つの関数を適切にオーバーライドする必要があります。
実装例
以下のような感じにしました。
※とりいそぎで書いているので、最後のコンソール出力はソートせずにdictionaryに入れた順で出しちゃってます。
※foreachのループの中でループカウンタをとってくる方法は、もっといいやり方があるかも…
社員クラス
public class Employee
{
public string id { get; set; }
public string name { get; set; }
// コンストラクタ
public Employee(string id, string name)
{
this.id = id;
this.name = name;
}
// Equalsをオーバーライド(※VisualStudioで自動生成)
public override bool Equals(object obj)
{
return obj is Employee employee &&
id == employee.id &&
name == employee.name;
}
// GetHashCodeをオーバーライド(※VisualStudioで自動生成)
public override int GetHashCode()
{
int hashCode = -48284730;
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(id);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(name);
return hashCode;
}
}
Main
// 結果の格納先
Dictionary<Employee, List<int>> dictionary = new Dictionary<Employee, List<int>>();
// 社員群
Employee john1 = new Employee("A0001", "John");
Employee tom = new Employee("A0002", "Tom");
Employee john2 = new Employee("A0003", "John");
Employee emily = new Employee("A0004", "Emily");
Employee alex = new Employee("A0005", "Alex");
// 記帳順のリスト
List<Employee> entryList = new List<Employee>()
{
john1,
tom,
john1,
emily,
alex,
john2,
john1,
john2,
alex
};
List<int> valueList;
int i = 0;
Console.WriteLine("--- 記帳順 ---");
// 記帳順を格納していく
foreach (Employee employee in entryList)
{
i++;
// dictionaryに登録済かを判定しつつ、登録済の場合はリストを取得
if (dictionary.TryGetValue(employee, out valueList))
{
// 登録済の場合、リストに値を追加して更新
valueList.Add(i);
dictionary[employee] = valueList;
}
else
{
// 初出の場合、登録
dictionary.Add(employee, new List<int> { i });
}
Console.WriteLine(string.Format("i={0}, {1}:{2}", i, employee.id, employee.name));
}
Console.WriteLine("--- 社員ごとの記録 ---");
// 結果を出力
foreach (Employee employee in dictionary.Keys)
{
Console.WriteLine(string.Format("{0}:{1} - {2}", employee.id, employee.name, string.Join(", ", dictionary[employee])));
}
結果
--- 記帳順 ---
i=1, A0001:John
i=2, A0002:Tom
i=3, A0001:John
i=4, A0004:Emily
i=5, A0005:Alex
i=6, A0003:John
i=7, A0001:John
i=8, A0003:John
i=9, A0005:Alex
--- 社員ごとの記録 ---
A0001:John - 1, 3, 7
A0002:Tom - 2
A0004:Emily - 4
A0005:Alex - 5, 9
A0003:John - 6, 8
参考リンク
C#で自作クラス(カスタムクラス)をキーにする方法(Dictionary,HashSet)
↧