ch7/ch7-06 #153
Replies: 13 comments 10 replies
-
练习7.8// 1. 定义数据类型
type Person struct {
Name string
Age int
Sex bool
ID int
}
type PersonSlice []Person
// Less 没有实现sort.Interface的Less方法
func (p PersonSlice) Less(i, j int, field string) bool {
return PersonByField(p[i], p[j], field)
}
// PersonByField 按照字段排序
func PersonByField(i, j Person, field string) bool {
switch field {
case "Name":
return i.Name > j.Name
case "Age":
return i.Age < j.Age
case "Sex":
return i.Sex != j.Sex
case "ID":
return i.ID < j.ID
}
return false
}
func main() {
// 构建数据
data := PersonSlice{
{"a", 1, true, 1},
{"b", 2, false, 2},
{"c", 3, true, 3},
{"d", 4, false, 4},
{"e", 5, true, 5},
{"f", 6, false, 6},
{"g", 7, true, 7},
}
// 排序
sort.Slice(data, func(i, j int) bool {
return data.Less(i, j, "Sex")
})
// 输出
for _, v := range data {
fmt.Println(v)
}
// 尝试使用反射解决,可是发现不会,233333
t, b := reflect.TypeOf(data[1]).FieldByName("Name")
fmt.Println(t, b)
} |
Beta Was this translation helpful? Give feedback.
-
练习7.9文件 /Practice/7.9.gopackage main
import (
"Study/src/study/day9Interface/Practice/comm"
"html/template"
"log"
"net/http"
"os"
"sort"
)
// 使用html/template包(§4.6)替代printTracks将tracks展示成一个HTML表格。
// 将这个解决方案用在前一个练习中,让每次点击一个列的头部产生一个HTTP请求来排序这个表格。
const TEMPL = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!--额加个边框吧-->
<table border="1" cellspacing="0">
<tr>
<th><a href="/?sort=Name">Name</a></th>
<th><a href="/?sort=Age">Age</a></th>
<th><a href="./?sort=Sex">Sex</a></th>
<th><a href="./?sort=ID">ID</a></th>
</tr>
{{range .}}
<tr>
<td>{{.Name}}</td>
<td>{{.Age}}</td>
<td>{{.Sex}}</td>
<td>{{.ID}}</td>
</tr>
{{end}}
</table>
</body>
</html>
`
func main() {
// 构建数据
data := comm.PersonSlice{
{"a", 1, true, 1},
{"b", 2, false, 2},
{"c", 3, true, 3},
{"d", 4, false, 4},
{"e", 5, true, 5},
{"f", 6, false, 6},
{"g", 7, true, 7},
}
// 构建模版
templ, err := template.New("test").Parse(TEMPL)
if err != nil {
log.Fatalln(err)
}
templ.Execute(os.Stdout, data)
// 注册web
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// 排序
sort.Slice(data, func(i, j int) bool {
// 获得sort参数
return data.Less(i, j, r.FormValue("sort"))
})
// 输出
templ.Execute(w, data)
})
// 监听
http.ListenAndServe(":8080", nil)
}文件 /Practice/comm/comm.gopackage comm
type Person struct {
Name string
Age int
Sex bool
ID int
}
type PersonSlice []Person
// Less 没有实现sort.Interface的Less方法
func (p PersonSlice) Less(i, j int, field string) bool {
return PersonByField(p[i], p[j], field)
}
// PersonByField 按照字段排序
func PersonByField(i, j Person, field string) bool {
switch field {
case "Name":
return i.Name > j.Name
case "Age":
return i.Age < j.Age
case "Sex":
return i.Sex != j.Sex
case "ID":
return i.ID < j.ID
}
return false
} |
Beta Was this translation helpful? Give feedback.
-
练习 7.10package main
import (
"fmt"
"sort"
"strings"
)
func IsPalindrome(s sort.Interface) bool {
for i, j := 0, s.Len()-1; i < j; i, j = i+1, j-1 {
if s.Less(i, j) || s.Less(j, i) {
return false
}
}
return true
}
func StrToSlice(str string) []string {
return strings.Split(str, "")
}
func IntToSlice(num int) []int {
var s []int
for num > 0 {
s = append(s, num%10)
num /= 10
}
return s
}
func main() {
var str = "abcdcba"
// 将字符串转为[]string
s := StrToSlice(str)
fmt.Println(str, ":", IsPalindrome(sort.StringSlice(s))) // abcdcba : true
var num = 123321
// 将数字转为[]int
nums := IntToSlice(num)
fmt.Println(num, ":", IsPalindrome(sort.IntSlice(nums))) // 123321 : true
num = 123456
nums = IntToSlice(num)
fmt.Println(num, ":", IsPalindrome(sort.IntSlice(nums))) // 123456 : false
} |
Beta Was this translation helpful? Give feedback.
-
|
真是理解不了 |
Beta Was this translation helpful? Give feedback.
-
|
[]int没有实现sort.Interface, 而sort.Reverse要求参数是sort.Interface类型,因此需要用其内置的IntSlice类型包装一下。上面的sort.Ints本质上也是如此,函数内部自动对[]int类型进行了包装。sort.IntsAreSorted也是用sort.IntSlice类型对传入的[]int类型进行一层包装,然后再调用IntSlice的Less函数进行比较的, 默认是从小到大的顺序。 |
Beta Was this translation helpful? Give feedback.
-
|
机器翻译痕迹太重了 |
Beta Was this translation helpful? Give feedback.
-
7.10package main
import (
"fmt"
"sort"
)
func main() {
// 测试
t1 := []int{1, 2, 3, 2, 1}
fmt.Println(isPalindrome(sort.IntSlice(t1)))
t2 := []string{"hello", "world", "hello"}
fmt.Println(isPalindrome(sort.StringSlice(t2)))
t3 := []string{"hello", "world", "hell"}
fmt.Println(isPalindrome(sort.StringSlice(t3)))
}
func isPalindrome(s sort.Interface) bool {
for i, j := 0, s.Len()-1; i < j; i, j = i+1, j-1 {
// 两边依次比较,有不同则跳出
if s.Less(i, j) || s.Less(j, i) {
return false
}
}
return true
} |
Beta Was this translation helpful? Give feedback.
-
|
// Reverse returns the reverse order for data. |
Beta Was this translation helpful? Give feedback.
-
|
这个接口的设计还是挺奇怪的 Less(i, j int) bool比较功能设计的入参不是两个元素相比较,而是两个index,这相当于从一开始就默认了需要排序的集合是数组或slice,这样才能通过index拿到具体元素 func (x customSort) Swap(i, j int)实际上对于slice或数组,它的swap只能是下面这样吧 { x.t[i], x.t[j] = x.t[j], x.t[i] }我感觉这种别扭的设计是因为golang没在一开始引入泛型的原因,要是引入了泛型,比较接口应该设计为: Less(this,that T) bool |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
|
7.10 func IsPalindrome(s sort.Interface) bool {
n := s.Len()
i, j := 0, n-1
for i < j {
if !(!s.Less(i, j) && !s.Less(j, i)) {
return false
}
i++
j--
}
return true
} |
Beta Was this translation helpful? Give feedback.
-
package main
import (
"fmt"
"os"
"reflect"
"sort"
"text/tabwriter"
"time"
)
// 练习 7.8:
// 很多图形界面提供了一个有状态的多重排序表格插件:主要的排序键是最近一次点击过列头的列,第二个排序键是第二最近点击过列头的列,等等。
// 定义一个sort.Interface的实现用在这样的表格中。比较这个实现方式和重复使用sort.Stable来排序的方式。
type Track struct {
Title string
Artist string
Album string
Year int
Length time.Duration
}
func length(s string) time.Duration {
d, err := time.ParseDuration(s)
if err != nil {
panic(s)
}
return d
}
func printTracks(tracks []*Track) {
const format = "%v\t%v\t%v\t%v\t%v\t\n"
tw := new(tabwriter.Writer).Init(os.Stdout, 0, 8, 2, ' ', 0)
fmt.Fprintf(tw, format, "Title", "Artist", "Album", "Year", "Length")
fmt.Fprintf(tw, format, "-----", "------", "-----", "----", "------")
for _, t := range tracks {
fmt.Fprintf(tw, format, t.Title, t.Artist, t.Album, t.Year, t.Length)
}
tw.Flush() // calculate column widths and print table
}
// 多字段排序
type fieldsSort struct {
t []*Track
fields []string
}
func (x fieldsSort) Len() int { return len(x.t) }
func (x fieldsSort) Less(i, j int) bool {
o1, o2 := x.t[i], x.t[j]
v1, v2 := reflect.ValueOf(o1), reflect.ValueOf(o2)
t1 := reflect.TypeOf(o1)
if t1.Kind() == reflect.Pointer {
t1 = t1.Elem()
v1 = v1.Elem()
v2 = v2.Elem()
}
for _, fieldName := range x.fields {
_, ok := t1.FieldByName(fieldName)
if !ok {
// 字段不存在,跳过(或者可以 panic 提示错误)
continue
}
r1 := v1.FieldByName(fieldName)
r2 := v2.FieldByName(fieldName)
// 如果字段不可比较,跳过
if !r1.IsValid() || !r2.IsValid() {
continue
}
switch r1.Type().Kind() {
case reflect.String:
s1, s2 := r1.String(), r2.String()
if s1 == s2 {
continue
}
return s1 < s2
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i1, i2 := r1.Int(), r2.Int()
if i1 == i2 {
continue
}
return i1 < i2
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
u1, u2 := r1.Uint(), r2.Uint()
if u1 == u2 {
continue
}
return u1 < u2
case reflect.Float32, reflect.Float64:
f1, f2 := r1.Float(), r2.Float()
if f1 == f2 {
continue
}
return f1 < f2
case reflect.Bool:
b1, b2 := r1.Bool(), r2.Bool()
if b1 == b2 {
continue
}
// false < true
return !b1 && b2
default:
// 不支持的类型,跳过该字段
// 可以考虑记录警告或返回错误
continue
}
}
// 所有字段都相等,返回 false(i 不小于 j)
return false
}
func (x fieldsSort) Swap(i, j int) { x.t[i], x.t[j] = x.t[j], x.t[i] }
func main() {
var tracks = []*Track{
{"Go", "Delilah", "From the Roots Up", 2012, length("3m38s")},
{"Go", "Moby", "Moby", 1992, length("3m37s")},
{"Go Ahead", "Alicia Keys", "As I Am", 2007, length("4m36s")},
{"Ready 2 Go", "Martin Solveig", "Smash", 2011, length("4m24s")},
}
sort.Sort(fieldsSort{tracks, []string{"Title", "Year"}})
printTracks(tracks)
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
ch7/ch7-06
中文版
https://golang-china.github.io/gopl-zh/ch7/ch7-06.html
Beta Was this translation helpful? Give feedback.
All reactions