こんにちは。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ですね。