解答: Filter¶
keep が true を返した要素だけを append して、新しいスライスを返します。
元の items は変更しません。
In [1]:
func Filter[T any](items []T, keep func(T) bool) []T {
result := []T{}
for _, item := range items {
if keep(item) {
result = append(result, item)
}
}
return result
}
チェック(問題ノートブックと同じ期待値)¶
In [2]:
import "reflect"
import "fmt"
func mustEqual(got, want any, name string) {
if reflect.DeepEqual(got, want) {
fmt.Printf("✅ Passed: %s\n", name)
return
}
panic(fmt.Sprintf("❌ %s\n got = %v (%T)\n want = %v (%T)", name, got, got, want, want))
}
In [3]:
%%
evens := Filter([]int{1, 2, 3, 4, 5}, func(x int) bool { return x%2 == 0 })
mustEqual(evens, []int{2, 4}, "偶数だけ残す (int)")
shorts := Filter([]string{"cat", "elephant", "dog", "hippopotamus"}, func(s string) bool {
return len(s) <= 3
})
mustEqual(shorts, []string{"cat", "dog"}, "3 文字以下だけ残す (string)")
allEmpty := Filter([]int{}, func(x int) bool { return x > 0 })
mustEqual(allEmpty, []int{}, "空スライスは空を返す")
println("🎉 すべてのチェックが通りました")
✅ Passed: 偶数だけ残す (int) ✅ Passed: 3 文字以下だけ残す (string) ✅ Passed: 空スライスは空を返す
🎉 すべてのチェックが通りました
解説¶
result := []T{}— 結果を入れる空のスライスを作ります。Tはジェネリクスの型パラメータなので、intでもstringでも、この 1 つのコードで動きますfor _, item := range items— 元の順序を保ったまま 1 つずつ見ますif keep(item) { result = append(...) }— 条件を満たすものだけ残します
Filter([]int{...}) でも Filter([]string{...}) でも同じコードが動くのは、
ジェネリクスで型をパラメータ化したからです。型ごとに同じ関数を書く必要がありません。