113 lines
2.6 KiB
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")
|
|
}
|