Blog ブログ

へっぽこプログラマの奮闘記 ~第2回:LinqのGroupByにこんな機能が!?~

どうもこんにちは。プログラマの田中智大です。
7月になり今年も半分が過ぎました。今月は任天堂Switchと某イカのゲームが欲しいのですが、Switchがなかなか手に入らなくて苦労しています。
欲しいですね・・・、任天堂Switch・・・・・

さて、ブログの本題に入りますが、サーバーのデータベースにあるSQLデータを扱う時にC#のLinqってとても便利ですね。WhereとかSelectとか使ってると楽しいですよー!
そんなある日、データをこんな形でGroupByしたい時がやってきました。

これに対して私の書いたプログラムをご覧ください。

動くには動くけど、ネストだらけで読みづらい へっぽこコード です。

実はこれ、こんな書き方ができるんです!

        匿名型↓
var groupedData = dataList.GroupBy(x => new { x.Type, x.Name, x.Coupon });

通称「複数キー」と呼ばれているもので、匿名型を使うと、たった1行だけであのへっぽこネストが解消されちゃいます!!

この仕組みが知りたくてMSDNのEnumerable.GroupByを読んでみたのですが・・・

あれ!?ドキュメントに匿名型使う機能なんて書いてない!!!」という事態にぶち当たってしまいました・・・
実はよく調べると、今回の振り分ける機能は「使っているのはGroupByの機能だけではない!」ということなんです。どういう事かをもう少し詳しく説明しましょう。

まず、匿名型は意外にもこう見えて EqualsメソッドGetHashCodeメソッド をちゃんと持っています(ぱっと見で単純な構造してるけどね)
今回は匿名型のデフォルトの比較子である Equalsメソッド を使っています。

そしてGroupByはいたって普通の
Enumerable.GroupBy<TSource, TKey> (IEnumerable<TSource>, Func<TSource, TKey>)
を使っています。

MSDNのドキュメントには短く「既定の等値比較子 Default キーを比較するために使用します。」と書かれていますが、これは具体的に言うと「キー同士の比較にはEqualityComparer<T>.Defaultプロパティが使われています」という事です。
※ちなみにEqualityComperer<T>.DefaultはTの型のデフォルトの比較子を返します。

つまり、このFunc<TSource, TKey>のキーセレクタに匿名型を入れた場合、「匿名型のEqualsメソッド」でキーを比較するようになります。そして匿名型の Equalsメソッド は「すべてのプロパティが等しいとき」に等しいと判定されます(逆に言えば一つでもプロパティが異なれば、それは違うものと判定されます)

さて、ここまでの説明から「なぜ匿名型を使う事で複数キーが分別できるか」の理由がお分かりいただけましたでしょうか?
グループ分けの際に匿名型のプロパティが全て同じものでグループ分けを行っているため、複数のキーの組み合わせそれぞれでグループ分けができるんです。

まとめ

匿名型を使ったグループ分けは「GroupByが匿名型を使ったら複数のキーでグループ分けできる」というよりは「GroupByのキーセレクタに匿名型を使うと、その匿名型のEqualsメソッドでキーの振り分けを行っている」という形になります。
 確かにMSDNドキュメントには「匿名型を使うと複数キーでグループ分けできる」とは書いていませんでしたが、この機能は「GroupByはデフォルトのEqualsメソッドを使ってキーの判別を行っている」ということと「匿名型のEqualsメソッドはデフォルトで全てのプロパティが同じな場合に等しいと判定する」という二つの機能を合わせたものだったんですね!
“言語の機能を理解するとできることの幅が広がる”とはこういうことなんだと実感します。

おわりに

入社して間も無い頃はLinqはおろか、IEnumerableすら何かわからなかった状態でした。ですが、先輩に教えてもらったり、ドキュメント読んで勉強したりしてだいぶ分かってきた今、Linqをとても楽しく使っています(目指せLinqマスター!)
また新しい機能とか使い方勉強してどんどん使っていきたいですね!


採用情報

クラウドクリエイティブスタジオではエンジニアの方を絶賛募集中です。
一緒に面白いゲームを作っていきましょう!

採用情報