RosettaCodeData/Task/Optional-parameters/Go/optional-parameters-5.go

113 lines
2.6 KiB
Go

package main
import (
"fmt"
"sort"
)
type cell string
type row []cell
type table struct {
rows []row
column int
less func(cell, cell) bool
}
func (c cell) String() string {
return fmt.Sprintf("%q", string(c))
}
func (t table) printRows(heading string) {
fmt.Println("--", heading)
for _, row := range t.rows {
fmt.Println(row)
}
fmt.Println()
}
// sort.Interface
func (t table) Len() int { return len(t.rows) }
func (t table) Swap(i, j int) { t.rows[i], t.rows[j] = t.rows[j], t.rows[i] }
func (t table) Less(i, j int) bool {
return t.less(t.rows[i][t.column], t.rows[j][t.column])
}
// struct implements named parameter-like capability
type spec struct {
ordering func(cell, cell) bool
column int
reverse bool
}
// A defined option type is not really needed by the technique, but has
// a nice advantage for documentation. If this type is exported, then
// the the Go documentation tool go doc will organize all of the option
// functions together under the type. (Go doc will see them as constructors
// for the type.)
type Option func(*spec)
func ordering(o func(cell, cell) bool) Option {
return func(s *spec) { s.ordering = o }
}
func column(c int) Option {
return func(s *spec) { s.column = c }
}
func reverse() Option {
return func(s *spec) { s.reverse = true }
}
func (t *table) sort(options ...Option) {
var s spec
for _, o := range options {
o(&s)
}
// set up column and comparison function for sort
t.column = s.column
switch {
case s.ordering != nil:
t.less = s.ordering
case s.reverse:
t.less = func(a, b cell) bool { return a > b }
default:
t.less = func(a, b cell) bool { return a < b }
}
// sort
sort.Sort(t)
// reverse if necessary
if s.ordering == nil || !s.reverse {
return
}
last := len(t.rows) - 1
for i := last / 2; i >= 0; i-- {
t.rows[i], t.rows[last-i] = t.rows[last-i], t.rows[i]
}
}
func main() {
t := table{rows: []row{
{"pail", "food"},
{"pillbox", "nurse maids"},
{"suitcase", "airedales"},
{"bathtub", "chocolate"},
{"schooner", "ice cream sodas"},
}}
t.printRows("song")
// no parameters
t.sort()
t.printRows("sorted on first column")
// "named parameter" reverse.
t.sort(reverse())
t.printRows("reverse sorted on first column")
// "named parameters" column and ordering
byLen := func(a, b cell) bool { return len(a) > len(b) }
t.sort(column(1), ordering(byLen))
t.printRows("sorted by descending string length on second column")
}