package main
import (
"fmt"
"sort"
)
func main() {
i := []int{5, 3, 2, 8, 7}
s := []string{"d", "a", "f"}
p := []struct {
Name string
Age int
}{
{"Nancy", 20},
{"Vera", 40},
{"Mike", 30},
{"Bob", 50},
}
// pスライスをNameフィールドでソート
sort.Slice(p, func(i, j int) bool { return p[i].Name < p[j].Name })
// ソートされたスライスを出力
fmt.Println(i, s, p)
}
解説
-
パッケージのインポート:
import ( "fmt" "sort" )
-
fmt
パッケージはフォーマットされたI/Oを提供します。 -
sort
パッケージはスライスやコレクションのソート機能を提供します。
-
-
main関数:
func main() {
-
main
関数はプログラムのエントリーポイントです。
-
-
スライスの定義:
i := []int{5, 3, 2, 8, 7} s := []string{"d", "a", "f"} p := []struct { Name string Age int }{ {"Nancy", 20}, {"Vera", 40}, {"Mike", 30}, {"Bob", 50}, }
-
i
は整数のスライスです。 -
s
は文字列のスライスです。 -
p
は構造体のスライスで、各要素はName
フィールドとAge
フィールドを持ちます。
-
-
スライスのソート:
sort.Slice(p, func(i, j int) bool { return p[i].Name < p[j].Name })
-
sort.Slice
関数はスライスをソートするために使用されます。 - 匿名関数
func(i, j int) bool
はソートの基準を定義します。この場合、p
スライスの要素のName
フィールドに基づいてソートします。
-
-
出力:
fmt.Println(i, s, p)
-
fmt.Println
関数は引数として渡された値を標準出力に表示します。 - この場合、ソートされていない整数スライス
i
と文字列スライスs
、およびソートされた構造体スライスp
が出力されます。
-
実行結果 (期待されるもの)
p
スライスはName
フィールドに基づいてアルファベット順にソートされます。よって、出力は次のようになります:
[5 3 2 8 7] [d a f] [{Bob 50} {Mike 30} {Nancy 20} {Vera 40}]
整数スライス i
と文字列スライス s
はソートされていないため、そのままの順序で出力されます。
ソートの仕組み
sort.Slice
関数は内部的にソートアルゴリズム(例えば、クイックソートやマージソート)を使用します。このアルゴリズムは、要素間の大小関係を比較し、その結果に基づいて要素を並べ替えます。
比較関数の役割
ソートアルゴリズムが動作するためには、要素同士を比較する方法が必要です。Goのsort.Slice
では、これを比較関数(less
関数)によって提供します。この関数は、2つの要素のインデックスi
とj
を受け取り、それらの要素の順序を決定します。
p[i].Name < p[j].Name
の意味
具体的にこの部分:
func(i, j int) bool { return p[i].Name < p[j].Name }
は、次のように解釈されます:
-
p[i].Name < p[j].Name
がtrue
の場合、p[i]
はp[j]
よりも前に来るべきだと判断されます。 -
p[i].Name < p[j].Name
がfalse
の場合、p[i]
はp[j]
よりも後に来るべきだと判断されます。
ソートアルゴリズムの動作
ソートアルゴリズムは、この比較関数を用いて以下のように動作します:
-
要素の比較:
- ソートアルゴリズムは、スライスの異なる要素のペアを選び出します。
- 比較関数にそのペアのインデックスを渡して、どちらの要素が先に来るべきかを判断します。
-
要素の交換:
- 比較関数の結果に基づいて、要素を適切な順序に並べ替えます。
- 例えば、
p[i].Name < p[j].Name
がtrue
ならば、p[i]
がp[j]
の前に来るようにします。
-
繰り返し:
- このプロセスを必要な回数だけ繰り返し、最終的に全ての要素が正しい順序に並ぶようにします。
具体例
例えば、以下のようなスライスp
があるとします:
p := []struct {
Name string
Age int
}{
{"Nancy", 20},
{"Vera", 40},
{"Mike", 30},
{"Bob", 50},
}
-
初回比較:
- 比較関数が
p[0]
("Nancy")とp[1]
("Vera")を比較します。 -
p[0].Name < p[1].Name
("Nancy" < "Vera")はtrue
なので、順序はそのまま。
- 比較関数が
-
次の比較:
-
p[2]
("Mike")とp[3]
("Bob")を比較します。 -
p[2].Name < p[3].Name
("Mike" < "Bob")はfalse
なので、これらの要素を交換します。
-
-
交換後:
- 交換後のスライスは次のようになります:
p := []struct { Name string Age int }{ {"Nancy", 20}, {"Vera", 40}, {"Bob", 50}, {"Mike", 30}, }
- 交換後のスライスは次のようになります:
-
さらに比較を続ける:
- このようにして、アルゴリズムは全ての要素ペアを比較し、適切な順序に並べ替えます。
最終的に、スライスp
はName
フィールドに基づいて昇順にソートされます。このように、less
関数がソートアルゴリズムに対して、要素の順序を決定するための基準を提供することで、スライスが正しく並び替えられるのです。