技術と趣味の亜空間

主にゲームプログラミングとその周辺に関する記事を不定期で上げていきます

GroupByで配列を含む複数のキーから要素をグループ化できるようにする

概要

例えば、以下のようなデータがあります。

class Book
{
    public int Id { get; set; }
    public int CityId { get; set; }
    public int[] ReferenceIds { get; set; }
}

var data = new List<Book>()
{
    new Book { Id = 1, CityId = 1, ReferenceIds = new int[]{ 1 } },
    new Book { Id = 2, CityId = 1, ReferenceIds = new int[]{ 1 } },
    new Book { Id = 3, CityId = 1, ReferenceIds = new int[]{ 9, 1 } },
    new Book { Id = 4, CityId = 2, ReferenceIds = new int[]{ 1 } },
    new Book { Id = 5, CityId = 1, ReferenceIds = new int[]{ 5 } },
};

ここから、LINQGroupBy()を用いてReferenceIdsの配列数と中身の値が全て同一、かつCityIdが同じ場合は1つのグループとにまとめたい状況を考えます。
(上のコードだと、Idが1と2のクラスは1つにまとまり、それ以外のデータは別々のグループになるようにしたい)

このグループ化は、デフォルトで用意されている複数キーを使ったGroupByだと上手くまとまらなかったので、 IEqualityComparer を用いてグループ化の条件を自作します。

サンプルコード

今回はTupleを利用して複数のキーをまとめて1つのキーとみなし、IEqualityComparerを継承した等値比較クラスで判定します。

実行結果

■Group CityId:1, RefIdsLen:1
┗Id:1, CityId:1, RefIdsLen:1, RefIds:1
┗Id:2, CityId:1, RefIdsLen:1, RefIds:1
■Group CityId:1, RefIdsLen:2
┗Id:3, CityId:1, RefIdsLen:2, RefIds:9, 1
■Group CityId:2, RefIdsLen:1
┗Id:4, CityId:2, RefIdsLen:1, RefIds:1
■Group CityId:1, RefIdsLen:1
┗Id:5, CityId:1, RefIdsLen:1, RefIds:5

CityIdの値とReferenceIdsが同じものでグループ化されているのが確認できました。

おまけ

雑にやっていいならIEqualityComparerを利用せずReferenceIdsCityIdをString化して直接連結する方法でも実現可能。

var groupedDataList = data.GroupBy(d => string.Join(",", d.ReferenceIds.Append(d.CityId))).ToArray();