概要
2022年12月18日投稿の「CSV を GO でクィックソート 2」を一部修正します。
これは、「現場で使える実践テクニック みんなの言語 改訂2版」の中の第2章を読み理解したところで修正するものです。
「守るべき暗黙のルール」こう言ったことは、独学で書いている者にとって忘れているというよりも、全く気にすることがないことなので、目が覚める思いでした。
私が教科書にしている本です。
修正前のコード(mainのみ)
func main() { // ----------ここに追加 in, err := os.Open("./input.csv") if err != nil { log.Fatal(err) } defer in.Close() r := csv.NewReader(transform.NewReader(in, japanese.ShiftJIS.NewDecoder())) // records => [][]string records, err := r.ReadAll() if err != nil { log.Fatal(err) } QuickSort(records, 0, len(records)-1) // 書き込み先ファイル // ----------ここに追加 out, err := os.Create("./output.csv") if err != nil { log.Fatal(err) } defer out.Close() // 書き込み w := csv.NewWriter(transform.NewWriter(out, japanese.ShiftJIS.NewEncoder())) w.WriteAll(records) }
import に “path/filepath” を追加して、
in, err := os.Open("./input.csv")
を
cwd, err := os.Getwd()
if err != nil {
log.Fatal(err)
return
}
name := filepath.Join(cwd, "input.csv")
in, err := os.Open(name)
に変更すればいいのかなと実行してみたら
次のエラーが出ました。
cannot use records (variable of type [][]string) as type []string in argument to QuickSort
前回、コンパイルがなぜか通りましたが今回エラーになりました。
気を取り直し、見直してコンパイルが通ったコードは次の通りです。
修正後のコード(全コード)
package main import ( "encoding/csv" "log" "os" "strings" "path/filepath" "golang.org/x/text/encoding/japanese" "golang.org/x/text/transform" ) func QuickSort(elements [][]string, left int, right int) { if left < right { posi := getposi(elements, left, right) QuickSort(elements, left, posi-1) QuickSort(elements, posi+1, right) } } func getposi(elements [][]string, left int, right int) int { //軸を右端 pivot := elements[right][0] //開始位置 i := left //昇順にするため左に小さいもののエリア for j := left; j < right; j++ { //pivotより小さいものが見つかった if strings.Compare(pivot, elements[j][0]) == 1 { swap(&elements[i], &elements[j]) //次の交換位置 i += 1 } } //pivotの位置iが定まったので交換 swap(&elements[i], &elements[right]) //位置を返す return i } func swap(element1 *([]string), element2 *([]string)) { val := (*element1)[0] (*element1)[0] = (*element2)[0] (*element2)[0] = val } func main() { cwd, err := os.Getwd() if err != nil { log.Fatal(err) return } name := filepath.Join(cwd, "input.csv") in, err := os.Open(name) if err != nil { log.Fatal(err) return } defer in.Close() r := csv.NewReader(transform.NewReader(in, japanese.ShiftJIS.NewDecoder())) // records => [][]string records, err := r.ReadAll() if err != nil { log.Fatal(err) return } QuickSort(records, 0, len(records)-1) // 書き込み先ファイル name = filepath.Join(cwd, "output.csv") out, err := os.Create(name) if err != nil { log.Fatal(err) return } defer out.Close() // 書き込み w := csv.NewWriter(transform.NewWriter(out, japanese.ShiftJIS.NewEncoder())) w.WriteAll(records) }
1列から2列のソート
左が前回の CSV ファイルです。今回は JAVA のクイックソートで使った CSV ファイルを使ってみます。
2列用に改良したコード
GO言語には、While ループがありませんので For ループを使います。ですので、ちょっと工夫しなければなりません。
package main import ( "encoding/csv" "log" "os" "strings" "path/filepath" "golang.org/x/text/encoding/japanese" "golang.org/x/text/transform" ) func QuickSort(elements [][]string, left int, right int) { if left < right { posi := getposi(elements, left, right) QuickSort(elements, left, posi-1) QuickSort(elements, posi+1, right) } } func getposi(elements [][]string, left int, right int) int { // 軸を中央値 mid := (left + right) / 2 // 右端の値と中央値を入れ替えます。 swap(&elements[right], &elements[mid]) // 開始位置・区切り位置 i := left // 昇順にするため左に小さいもののエリア for j := left; j < right; j++ { // pivotより小さいものが見つかった if ijcomp(elements, right, j) { swap(&elements[i], &elements[j]) // 次の交換位置 i += 1 } } // pivotの位置iが定まったので交換 swap(&elements[i], &elements[right]) // pivotの位置を返す return i } func ijcomp(elements [][]string, right int, j int) bool { // elements[right][0] > elements[j][0] なら res=1 res := strings.Compare(elements[right][0], elements[j][0]) if res == 0 { res = strings.Compare(elements[right][1], elements[j][1]) } return res >= 0 } func swap(element1 *([]string), element2 *([]string)) { val := (*element1)[0] (*element1)[0] = (*element2)[0] (*element2)[0] = val val = (*element1)[1] (*element1)[1] = (*element2)[1] (*element2)[1] = val } func main() { cwd, err := os.Getwd() if err != nil { log.Fatal(err) return } name := filepath.Join(cwd, "input.csv") in, err := os.Open(name) if err != nil { log.Fatal(err) return } defer in.Close() r := csv.NewReader(transform.NewReader(in, japanese.ShiftJIS.NewDecoder())) // records => [][]string records, err := r.ReadAll() if err != nil { log.Fatal(err) return } QuickSort(records, 0, len(records)-1) // 書き込み先ファイル name = filepath.Join(cwd, "output.csv") out, err := os.Create(name) if err != nil { log.Fatal(err) return } defer out.Close() // 書き込み w := csv.NewWriter(transform.NewWriter(out, japanese.ShiftJIS.NewEncoder())) w.WriteAll(records) }
実行結果
JAVA と同じ内容になりました。
実行ファイルをクリックしてソート結果が書き出されるまでの時間は2~3秒と JAVA と同じような結果になりました。
今日はここまでとします。