こんにちは。scarvizです。
明けましておめでとうございます。
今年もよろしくお願いします!
ということで、今回はGo言語のソートの仕方を紹介します。
「$GOROOT/src/pkg/sort/sort.go」のソースコードを参考にしました。
■あらかじめ用意されているソート関数を使う
Go言語はスライス型か自分で定義した型のソートが出来るようになっています。
スライス型でソートできるのはint,float64,stringの3種類のみです。
int32やint64、float32などは型変換するか、後で説明する「自分で定義した型のソートをする」を参考にしてください。
ソート関数を使う手順は以下になります。
1. sortをインポートする
2. それぞれのソート関数を呼び出す
intの場合はsort.Ints、float64の場合はsort.Float64s、stringの場合はsort.Stringsを呼び出します。
引数で渡したスライスが昇順になって返ってきます。
また、既にソートされているかどうかをチェックする関数もあります。
intの場合はsort.IntsAreSorted、float64の場合はsort.Float64sAreSorted、stringの場合はsort.StringsAreSortedを呼び出します。
既にソート済みの場合はtrue、未ソートの場合はfalseが返ってきます。
以下に使用例を記載します。
package main
import (
"fmt"
"sort"
)
func main() {
dataInt := []int{9, 3, 6, 7, 4, 1, 2, 8, 5}
sort.Ints(dataInt)
fmt.Println("dataInt:", dataInt)
dataFloat64 := []float64{9, 3, 6, 7, 4, 1, 2, 8, 5}
sort.Float64s(dataFloat64)
fmt.Println("dataFloat64:", dataFloat64)
dataString := []string{"d", "g", "b", "j", "c", "i", "a", "f", "e", "h"}
sort.Strings(dataString)
fmt.Println("dataString:", dataString)
var isSort bool
isSort = sort.IntsAreSorted(dataInt)
fmt.Println("dataInt Sorted:", isSort)
isSort = sort.Float64sAreSorted(dataFloat64)
fmt.Println("dataFloat64 Sorted:", isSort)
isSort = sort.StringsAreSorted(dataString)
fmt.Println("dataString Sorted:", isSort)
}
結果:
dataInt: [1 2 3 4 5 6 7 8 9] dataFloat64: [1 2 3 4 5 6 7 8 9] dataString: [a b c d e f g h i j] dataInt Sorted: true dataFloat64 Sorted: true dataString Sorted: true
■自分で定義した型のソートをする
あらかじめ用意されているソート関数はインターフェースを使っているので、これを利用して、自分で定義した型のソートをする関数を作ることが出来ます。
インターフェースで定義されている関数は以下になります。
// スライスの長さを取得する Len() int // 要素の大小を比較してiが小さいかどうかを判断する Less(i, j int) bool // 要素を入れ替える Swap(i, j int)
試しにint32がソートできるようにしてみようと思います。
1. 型を定義する
int32のスライスを型定義します。
type myInt32Slice []int32
2. インターフェースの関数を実装する
各関数を実装します。
func (p myInt32Slice) Len() int { return len(p) }
func (p myInt32Slice) Less(i, j int) bool { return p[i] < p[j] }
func (p myInt32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
3. ソート関数を実装する
int32のスライスを渡してソートできる関数を実装します。
func myInt32s(a []int32) { sort.Sort(myInt32Slice(a)) }
func myInt32SliceAreSorted(a []int32) bool { return sort.IsSorted(myInt32Slice(a)) }
4. ソートする
int32のスライスをソートしてみます。
package main
import (
"fmt"
"sort"
)
type myInt32Slice []int32
func (p myInt32Slice) Len() int { return len(p) }
func (p myInt32Slice) Less(i, j int) bool { return p[i] & lt; p[j] }
func (p myInt32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func myInt32s(a []int32) { sort.Sort(myInt32Slice(a)) }
func myInt32SliceAreSorted(a []int32) bool { return sort.IsSorted(myInt32Slice(a)) }
func main() {
dataInt32 := []int32{9, 3, 6, 7, 4, 1, 2, 8, 5}
myInt32s(dataInt32)
fmt.Println("dataInt32:", dataInt32)
isSort = myInt32SliceAreSorted(dataInt32)
fmt.Println("dataInt32 Sorted:", isSort)
}
結果:
dataInt32: [1 2 3 4 5 6 7 8 9] dataInt32 Sorted: true
■ソートメソッドを実装する
自分で定義した型なら、ソートメソッドを用意すると便利だと思います。
以下はstringのスライスを型定義したmyStringSliceで使ってみました。
package main
import (
"fmt"
"sort"
)
type myStringSlice []string
func (p myStringSlice) Len() int { return len(p) }
func (p myStringSlice) Less(i, j int) bool { return p[i] & lt; p[j] }
func (p myStringSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// ソートメソッド
func (p myStringSlice) Sort() { sort.Sort(p) }
func main() {
var dataMyString myStringSlice
dataMyString = []string{"d", "g", "b", "j", "c", "i", "a", "f", "e", "h"}
dataMyString.Sort()
fmt.Println("dataMyString:", dataMyString)
}
結果:
dataMyString: [a b c d e f g h i j]
ソートは良く使うと思うので、知っておくと便利ですね。
ちなみにお気付きかもしれませんが、Less関数を実装する時に、大小比較を逆しておくと降順でソートするようにできます。
みなさんも色々試してみてください!
そうそう。構造体のスライスをソートするようにするとめっちゃ便利と思います。
返信削除基本的には記事通りに実装して、Less関数は構造体で定義しているもののどれを比較するか指定すればOKですね。