この場合、普通の入力とは異なり、一括で処理するゆえのメンドクササがありますよね。
たとえば、ユーザ情報を外部システムからインポートする場合。想定するケースによりますが、ユーザIDがインポートデータ中に重複して存在する可能性があったりすると、せめて取り込みの事前のチェックを行っておきたいケースもあると思います。が、これが結構面倒。
これをGroupByメソッドを活用して、なるべくシンプルに記述してみます。想定する前提はこんな感じだとします。
- インポートするユーザ情報データは、すでにオブジェクトへのマッピングがされており、コレクション化されている前提。
- ユーザ情報データは「UserInfo」クラスに格納されており、ユーザIDは文字列のメンバUserIdとして存在する。
- ユーザ情報データのコレクションを入力として、ユーザIDの重複チェックを行う静的メソッド「ValidateNotDuplicated」を作成する。
- このメソッドは、ユーザIDの重複があった場合、コンソールにエラーメッセージを出力し、メソッドの戻り値はfalseを返す。重複がなければそのままtrueを返す。
- エラーメッセージには、重複しているユーザIDを表示する。複数のユーザIDが重複していた場合は、そのすべてを表示する。
このような処理を書くと、こんな感じになりますね。
public static bool ValidateNotDuplicated(IEnumerable<UserInfo> users) { var dupusers = users.GroupBy(u => u.UserId) .Where(g => g.Count() > 1) .Select(g => g.Key) .ToArray(); if (dupusers.Length > 0) { Console.WriteLine("User:{0} was duplicated.", string.Join(",", dupusers); return false; } return true; }
つまり、「コレクションをUserIdでグループ化し(GroupBy)」、「そのうち2つ以上存在するものを選び出し(Where)」、「キーとなっているUserIdのみを対象として(Select)」、「配列に変換する(ToArray)」。という処理を行っています。
ちょっとだけバリエーションを考えて見ましょうか。たとえば、
ちょっとだけバリエーションを考えて見ましょうか。たとえば、
- 「UserInfo」クラスには、データが更新された時間を示す「Updated」メンバ(DateTime型)も持っている。
- このユーザ情報データのコレクションを入力として、ユーザIDが重複していた場合、「Updated」が最新のもの以外を取り除いたコレクションを返す、静的メソッド「SelectLatest」を作成する。
この場合ならもっとシンプルで、
public static IEnumerable<UserInfo> SelectLatest(IEnumerable<UserInfo> users) { return users.GroupBy(u => u.UserId) .Select(g => g.OrderByDescending(u => u.Updated).First()); }
これだけになりますね。