sort.Interface
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 74/107。
sort パッケージは、インターフェースベースの設計のもう一つの優れた例を提供します。カスタムコレクションを並べ替えるには、型が sort.Interface を実装する必要があります。
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}これら3つのメソッドによって、ソートアルゴリズムに必要なものがすべて提供されます。それは、collection の length、elements を比較する方法、そしてそれらを入れ替える方法です。カスタム構造体のスライスをソート可能にする方法は次のとおりです。
type Person struct {
Name string
Age int
}
type ByAge []Person
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func main() {
people := []Person{
{"Alice", 30},
{"Bob", 25},
{"Carol", 35},
}
sort.Sort(ByAge(people))
fmt.Println(people)
// [{Bob 25} {Alice 30} {Carol 35}]
}重要なポイントは、スライスに基づく名前付き型(ByAge)を作成することです。これにより、同じデータに対して異なる並べ替え動作を定義できます。代わりに、別のLess実装を持つByNameを作成して、アルファベット順に並べ替えることもできます。
型が sort.Interface を満たすと、sort.Sort()、sort.Reverse()、sort.IsSorted() と自動的に連携して動作します。
チャレンジ
簡単Go の sort.Interfaceの力を示す、ソート可能な product inventory system を構築しましょう!Product型を作成し、複数のソート戦略を実装することで、同じ collection を異なる方法でソートできるようにします。
コードを2つのファイルに分けて整理します。
product.go:product type とソートの実装を定義します。3つのフィールドを持つ
Productstruct を作成します。Name(string)、Price(float64)、Quantity(int)です。[]Productbased の2つの named types を作成します。ByPrice- price の ascending order で products をソートするためのものByQuantity- quantity の descending order(quantity が多いものから)で products をソートするためのもの
各 type は、
sort.Interfaceに必要な3つの methods、Len()、Less(i, j int)、Swap(i, j int)を実装する必要があります。Lessmethod が各 type の sort order を決定します。main.go:product inventory を構築してソートします。sort mode(
priceまたはquantity)を読み取り、続けて count と product details を読み取ります。各 product は、name、price、quantity の3行で指定されます。products の slice を作成し、mode に基づいて適切な sorting type を使ってソートした後、各 product を次の format で表示します。
[Name]: $[Price] (x[Quantity])prices は小数点以下2桁で表示します。
次の inputs が提供されます。
- 1行目:Sort mode(
priceまたはquantity) - 2行目:products の number
- 続く行:Product details(name、price、quantity - 1 product あたり3行)
たとえば、次のように指定した場合:
price
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25出力は次のようになります。
Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)また、次のように指定した場合:
quantity
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25出力は次のようになります。
Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)同じ product data でも、異なる named type を使うだけで異なる方法でソートできることに注目してください。types がsort.Interfaceを満たせば、standard library のsort.Sort()とシームレスに連携できます。
自分で試してみよう
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// ソートモードを読み取る
var mode string
fmt.Fscanln(reader, &mode)
// 製品の数を読み取る
var count int
fmt.Fscanln(reader, &count)
// 製品を読み取る
products := make([]Product, count)
for i := 0; i < count; i++ {
name, _ := reader.ReadString('\n')
name = strings.TrimSpace(name)
priceStr, _ := reader.ReadString('\n')
priceStr = strings.TrimSpace(priceStr)
price, _ := strconv.ParseFloat(priceStr, 64)
qtyStr, _ := reader.ReadString('\n')
qtyStr = strings.TrimSpace(qtyStr)
quantity, _ := strconv.Atoi(qtyStr)
products[i] = Product{Name: name, Price: price, Quantity: quantity}
}
// TODO: モードに基づいて製品をソートする
// mode が "price" の場合、ByPrice 型を使用する
// mode が "quantity" の場合、ByQuantity 型を使用する
// 適切な型で sort.Sort() を使用する
// TODO: 各製品を次の形式で出力する:
// [Name]: $[Price] (x[Quantity])
// 価格のフォーマットに %.2f を使って fmt.Printf を使用する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー11標準ライブラリとOOP
io.Reader と io.Writersort.Interfacefmt.Stringer インターフェースencoding/json と構造体http.Handler インターフェースまとめ:REST API モデル自分で練習してみよう: Goオンラインコンパイラ