[小ネタ][Golang]go-linqでLINQ風の検索をしてみた

2021.12.14

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

go-linq という LINQ 風に検索できるライブラリを試してみました。使い方自体は go-linq のREADMEを見れば分かったのですが、自分なりにも試してみたいと思い、以前 紹介した gofakeit と組み合わせサンプルプログラムを書いてみました。

以下、そのサンプルプログラムについてとなります。

プログラムと実行について

Golangを実行できる環境にて、「go get」で予め使用するライブラリをインストールしておきます。

$ go get github.com/brianvoe/gofakeit/v6
$ go get github.com/ahmetb/go-linq/v3

今回書いたプログラムは以下となります。以前と同様「gofakeit」でビールに関するダミーデータを作り、そのデータから「go-linq」を使ってビールのモルト(Malt)数での逆ソート、モルト毎のカウントをやってみました。

package main

import (
	"fmt"
	"strings"

	. "github.com/ahmetb/go-linq/v3"
	"github.com/brianvoe/gofakeit"
)

type Beer struct {
	ID    int    `csv:"id"`
	Malt  string `csv:"malt"`
	Name  string `csv:"name"`
	Style string `csv:"style"`
}

func main() {
	gofakeit.Seed(0)

	var beers []Beer
	for i := 0; i < 10; i++ {
		b := &Beer{
			gofakeit.Number(1, 100),
			gofakeit.BeerMalt(),
			gofakeit.BeerName(),
			gofakeit.BeerStyle(),
		}
		beers = append(beers, *b)
	}

	for _, b := range beers {
		fmt.Printf("id : %v, malt : %s, name : %s\n", b.ID, b.Malt, b.Name)
	}

	var malts []string
	From(beers).
		Select(func(b interface{}) interface{} {
			return b.(Beer).Malt
		}).
		GroupBy(
			func(malt interface{}) interface{} {
				return malt
			}, func(malt interface{}) interface{} {
				return malt
			}).
		OrderByDescending(
			func(g interface{}) interface{} {
				return len(g.(Group).Group)
			}).
		Select(
			func(g interface{}) interface{} {
				return g.(Group).Key
			}).
		ToSlice(&malts)

	for _, m := range malts {
		c := From(beers).Where(func(b interface{}) bool {
			return strings.Contains(b.(Beer).Malt, m)
		}).Select(func(b interface{}) interface{} {
			return b.(Beer).Name
		}).Count()
		fmt.Printf("malt = %s, count = %v\n", m, c)
	}
}

19〜30行目で「gofakeit」を使ってダミーデータを生成しています。この辺りは以前とかわっておりません。「go-linq」を使った検索は36行目以降となります。36〜55行目で、ビール毎のモルト(Malt)の数で逆順でソートしています。構文的にはループを使わず「GroupBy()」や「OrderByDescending()」を使って検索していることが分かるかと思います。次に58〜62行目で、モルト(Malt)毎のカウントを行なっております。こちらもモルト毎のカウント自体にはループを使わず「Count()」を使っております。

実行してみると、以下のように生成したダミーデータ、モルト(Malt)数の逆順でカウントした結果が出力されます。(※ダミーデータはランダムで生成となるので毎回実行結果は異なります)

id : 5, malt : Victory, name : Péché Mortel
id : 36, malt : Roasted barley, name : Yeti Imperial Stout
id : 89, malt : Rye malt, name : Maudite
id : 83, malt : Vienna, name : La Fin Du Monde
id : 48, malt : Caramel, name : Sublimely Self-Righteous Ale
id : 57, malt : Rye malt, name : Founders Kentucky Breakfast
id : 64, malt : Special roast, name : Sierra Nevada Celebration Ale
id : 19, malt : Special roast, name : Samuel Smith’s Imperial IPA
id : 33, malt : Rye malt, name : Maharaj
id : 31, malt : Chocolate malt, name : Storm King Stout
malt = Rye malt, count = 3
malt = Special roast, count = 2
malt = Caramel, count = 1
malt = Chocolate malt, count = 1
malt = Victory, count = 1
malt = Roasted barley, count = 1
malt = Vienna, count = 1

sliceに複数件持たせたデータからの検索やカウントという良くある処理について、「Select()」「Groupby()」などで絞り込んでいけることが新鮮でした。何かの役に立てば幸いです。