回到简体

This commit is contained in:
chai2010
2016-02-15 11:06:34 +08:00
parent 9e878f9944
commit 2b37b23285
177 changed files with 2354 additions and 2354 deletions

View File

@@ -1,9 +1,9 @@
## 7.6. sort.Interface接口
排序操作和字符串格式化一是很多程序常使用的操作。管一最短的快排程序要15行就可以搞定但是一個健壯的實現需要更多的代碼,併且我不希望每次我需要的候都重或者拷貝這些代
排序操作和字符串格式化一是很多程序常使用的操作。管一最短的快排程序要15行就可以搞定但是一个健壮的实现需要更多的代码,并且我不希望每次我需要的候都重或者拷贝这些代
的是sort包置的提供了根一些排序函數來對任何序列排序的功能。它的設計非常到。在很多言中,排序算法都是和序列數據類型關聯,同排序函和具體類型元素關聯。相比之下Go言的sort.Sort函數不會對具體的序列和它的元素做任何假。相反,它使用了一接口型sort.Interface指定通用的排序算法和可能被排序到的序列型之間的約定。這個接口的實現由序列的具表示和它希望排序的元素定,序列的表示常是一切片。
的是sort包置的提供了根一些排序函数来对任何序列排序的功能。它的设计非常到。在很多言中,排序算法都是和序列数据类型关联,同排序函和具体类型元素关联。相比之下Go言的sort.Sort函数不会对具体的序列和它的元素做任何假。相反,它使用了一接口型sort.Interface指定通用的排序算法和可能被排序到的序列型之间的约定。这个接口的实现由序列的具表示和它希望排序的元素定,序列的表示常是一切片。
個內置的排序算法需要知道三個東西:序列的度,表示兩個元素比較的結果,一種交換兩個元素的方式;就是sort.Interface的三方法:
个内置的排序算法需要知道三个东西:序列的度,表示两个元素比较的结果,一种交换两个元素的方式;就是sort.Interface的三方法:
```go
package sort
@@ -15,7 +15,7 @@ type Interface interface {
}
```
爲了對序列行排序,我需要定義一個實現了這三個方法的型,然後對這個類型的一個實例應用sort.Sort函。思考對一個字符串切片行排序,可能是最簡單的例子了。下面是這個新的型StringSlice和它的LenLess和Swap方法
为了对序列行排序,我需要定义一个实现了这三个方法的型,然后对这个类型的一个实例应用sort.Sort函。思考对一个字符串切片行排序,可能是最简单的例子了。下面是这个新的型StringSlice和它的LenLess和Swap方法
```go
type StringSlice []string
@@ -24,21 +24,21 @@ func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p StringSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
```
在我可以通像下面這樣將一個切片轉換爲一個StringSlice類型來進行排序:
在我可以通像下面这样将一个切片转换为一个StringSlice类型来进行排序:
```go
sort.Sort(StringSlice(names))
```
這個轉換得到一相同度,容量,和基names數組的切片值;併且這個切片值的型有三排序需要的方法。
这个转换得到一相同度,容量,和基names数组的切片值;并且这个切片值的型有三排序需要的方法。
字符串切片的排序是很常用的需要所以sort包提供了StringSlice也提供了Strings函數能讓上面這些調用簡化成sort.Strings(names)。
字符串切片的排序是很常用的需要所以sort包提供了StringSlice也提供了Strings函数能让上面这些调用简化成sort.Strings(names)。
里用到的技很容易用到其它排序序列中,例如我可以忽略大些或者含有特殊的字符。(本使用Go程序索引詞和頁碼進行排序也用到了這個技術,對羅馬數字做了額外邏輯處理。)對於更複雜的排序,我使用相同的方法,但是用更複雜的數據結構和更複雜地實現sort.Interface的方法。
里用到的技很容易用到其它排序序列中,例如我可以忽略大些或者含有特殊的字符。(本使用Go程序索引词和页码进行排序也用到了这个技术,对罗马数字做了额外逻辑处理。)对于更复杂的排序,我使用相同的方法,但是用更复杂的数据结构和更复杂地实现sort.Interface的方法。
們會運行上面的例子來對一個表格中的音播放列表行排序。每track都是單獨的一行,每一列都是這個track的性像藝術家,標題,和運行時間。想象一個圖形用界面來呈現這個表格,併且點擊一個屬性的頂部會使這個列表按照這個屬性進行排序;再一次點擊相同性的頂部會進行逆向排序。讓我們看下每個點擊會發生什麽響應
们会运行上面的例子来对一个表格中的音播放列表行排序。每track都是单独的一行,每一列都是这个track的性像艺术家,标题,和运行时间。想象一个图形用界面来呈现这个表格,并且点击一个属性的顶部会使这个列表按照这个属性进行排序;再一次点击相同性的顶部会进行逆向排序。让我们看下每个点击会发生什么响应
下面的量tracks包好了一播放列表。One of the authors apologizes for the other authors musical tastes.)每元素都不是Track本身而是指向它的指針。盡管我在下面的代中直接存Tracks也可以工作sort函數會交換很多元素,所以如果每元素都是指針會更快而不是全部Track型,指是一個機器字碼長度而Track型可能是八或更多。
下面的量tracks包好了一播放列表。One of the authors apologizes for the other authors musical tastes.)每元素都不是Track本身而是指向它的指针。尽管我在下面的代中直接存Tracks也可以工作sort函数会交换很多元素,所以如果每元素都是指针会更快而不是全部Track型,指是一个机器字码长度而Track型可能是八或更多。
<u><i>gopl.io/ch7/sorting</i></u>
```go
@@ -66,7 +66,7 @@ func length(s string) time.Duration {
}
```
printTracks函數將播放列表打印成一表格。一個圖形化的展示可能更好,但是這個小程序使用text/tabwriter包生成一列是整齊對齊和隔的表格,像下面展示的這樣。註意到*tabwriter.Writer是滿足io.Writer接口的。它收集每一片向它的數據它的Flush方法格式化整表格併且將它寫向os.Stdout標準輸出)。
printTracks函数将播放列表打印成一表格。一个图形化的展示可能更好,但是这个小程序使用text/tabwriter包生成一列是整齐对齐和隔的表格,像下面展示的这样。注意到*tabwriter.Writer是足io.Writer接口的。它收集每一片向它的数据它的Flush方法格式化整表格并且将它写向os.Stdout标准输出)。
```go
func printTracks(tracks []*Track) {
@@ -81,7 +81,7 @@ func printTracks(tracks []*Track) {
}
```
了能按照Artist字段播放列表行排序,我們會像對StringSlice那樣定義一個新的有必LenLess和Swap方法的切片型。
了能按照Artist字段播放列表行排序,我们会像对StringSlice那样定义一个新的有必LenLess和Swap方法的切片型。
```go
type byArtist []*Track
@@ -90,13 +90,13 @@ func (x byArtist) Less(i, j int) bool { return x[i].Artist < x[j].Artist }
func (x byArtist) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
```
爲了調用通用的排序程序,我們必須先將tracks轉換爲新的byArtist型,它定了具的排序:
为了调用通用的排序程序,我们必须先将tracks转换为新的byArtist型,它定了具的排序:
```go
sort.Sort(byArtist(tracks))
```
在按照artist對這個切片行排序printTrack的出如下
在按照artist对这个切片行排序printTrack的出如下
```
Title Artist Album Year Length
@@ -107,13 +107,13 @@ Ready 2 Go Martin Solveig Smash 2011 4m24s
Go Moby Moby 1992 3m37s
```
如果用第二次求“按照artist排序”們會對tracks行逆向排序。然而我不需要定義一個有顛倒Less方法的新型byReverseArtistsort包中提供了Reverse函數將排序順序轉換成逆序。
如果用第二次求“按照artist排序”们会对tracks行逆向排序。然而我不需要定义一个有颠倒Less方法的新型byReverseArtistsort包中提供了Reverse函数将排序顺序转换成逆序。
```go
sort.Sort(sort.Reverse(byArtist(tracks)))
```
在按照artist對這個切片行逆向排序printTrack的出如下
在按照artist对这个切片行逆向排序printTrack的出如下
```
Title Artist Album Year Length
@@ -124,7 +124,7 @@ Go Delilah From the Roots Up 2012 3m38s
Go Ahead Alicia Keys As I Am 2007 4m36s
```
sort.Reverse函值得行更近一步的學習因爲它使用了(§6.3)章中的合,是一重要的思路。sort包定了一不公的struct型reverse它嵌入了一sort.Interface。reverse的Less方法調用了嵌的sort.Interface值的Less方法但是通過交換索引的方式使排序結果變成逆序。
sort.Reverse函值得行更近一步的学习因为它使用了(§6.3)章中的合,是一重要的思路。sort包定了一不公的struct型reverse它嵌入了一sort.Interface。reverse的Less方法用了嵌的sort.Interface值的Less方法但是通过交换索引的方式使排序结果变成逆序。
```go
package sort
@@ -136,9 +136,9 @@ func (r reverse) Less(i, j int) bool { return r.Interface.Less(j, i) }
func Reverse(data Interface) Interface { return reverse{data} }
```
reverse的另外兩個方法Len和Swap式地由原有嵌的sort.Interface提供。因reverse是一不公開的類型,所以出函Reverse函數返迴一個包含原有sort.Interface值的reverse類型實例。
reverse的另外两个方法Len和Swap式地由原有嵌的sort.Interface提供。因reverse是一不公开的类型,所以出函Reverse函数返回一个包含原有sort.Interface值的reverse类型实例。
了可以按照不同的列行排序,我們必須定義一個新的型例如byYear
了可以按照不同的列行排序,我们必须定义一个新的型例如byYear
```go
type byYear []*Track
@@ -147,7 +147,7 @@ func (x byYear) Less(i, j int) bool { return x[i].Year < x[j].Year }
func (x byYear) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
```
在使用sort.Sort(byYear(tracks))按照年tracks行排序printTrack展示了一個按時間先後順序的列表:
在使用sort.Sort(byYear(tracks))按照年tracks行排序printTrack展示了一个按时间先后顺序的列表:
```
Title Artist Album Year Length
@@ -158,7 +158,7 @@ Ready 2 Go Martin Solveig Smash 2011 4m24s
Go Delilah From the Roots Up 2012 3m38s
```
對於我們需要的每切片元素型和每排序函,我需要定義一個新的sort.Interface實現。如你所Len和Swap方法對於所有的切片型都有相同的定。下例子,具體的類型customSort會將一個切片和函數結合,使我們隻需要寫比較函數就可以定義一個新的排序。順便説下,實現了sort.Interface的具體類型不一定是切片customSort是一個結構體類型。
对于我们需要的每切片元素型和每排序函,我需要定义一个新的sort.Interface实现。如你所Len和Swap方法对于所有的切片型都有相同的定。下例子,具体的类型customSort会将一个切片和函数结合,使我们只需要写比较函数就可以定义一个新的排序。顺便说下,实现了sort.Interface的具体类型不一定是切片customSort是一个结构体类型。
```go
type customSort struct {
@@ -171,7 +171,7 @@ func (x customSort) Less(i, j int) bool { return x.less(x.t[i], x.t[j]) }
func (x customSort) Swap(i, j int) { x.t[i], x.t[j] = x.t[j], x.t[i] }
```
讓我們定義一個多層的排序函,它主要的排序鍵是標題,第二個鍵是年,第三個鍵是運行時間Length。下面是排序的調用,其中這個排序使用了匿名排序函
让我们定义一个多层的排序函,它主要的排序键是标题,第二个键是年,第三个键是运行时间Length。下面是排序的用,其中这个排序使用了匿名排序函
```go
sort.Sort(customSort{tracks, func(x, y *Track) bool {
@@ -188,7 +188,7 @@ sort.Sort(customSort{tracks, func(x, y *Track) bool {
}})
```
下面是排序的果。意到兩個標題是“Go”的track按照標題排序是相同的但是在按照year排序上更久的那track先。
下面是排序的果。意到两个标题是“Go”的track按照标题排序是相同的但是在按照year排序上更久的那track先。
```
Title Artist Album Year Length
@@ -199,7 +199,7 @@ Go Ahead Alicia Keys As I Am 2007 4m36s
Ready 2 Go Martin Solveig Smash 2011 4m24s
```
盡管對長度爲n的序列排序需要 O(n log n)次比操作,檢査一個序列是否已有序至少需要n1次比。sort包中的IsSorted函數幫我們做這樣的檢査。像sort.Sort一它也使用sort.Interface對這個序列和它的排序函數進行抽象,但是它從不會調用Swap方法段代示范了IntsAreSorted和Ints函和IntSlice型的使用:
尽管对长度为n的序列排序需要 O(n log n)次比操作,检查一个序列是否已有序至少需要n1次比。sort包中的IsSorted函数帮我们做这样的检查。像sort.Sort一它也使用sort.Interface对这个序列和它的排序函数进行抽象,但是它从不会调用Swap方法段代示范了IntsAreSorted和Ints函和IntSlice型的使用:
```go
values := []int{3, 1, 4, 1}
@@ -212,10 +212,10 @@ fmt.Println(values) // "[4 3 1 1]"
fmt.Println(sort.IntsAreSorted(values)) // "false"
```
了使用方便sort包[]int,[]string和[]float64的正常排序提供了特定版本的函數和類型。對於其他型,例如[]int64或者[]uint管路也很簡單,還是依賴我們自己實現
了使用方便sort包[]int,[]string和[]float64的正常排序提供了特定版本的函数和类型。对于其他型,例如[]int64或者[]uint管路也很简单,还是依赖我们自己实现
**練習 7.8** 很多形界面提供了一個有狀態的多重排序表格插件:主要的排序是最近一次點擊過列頭的列,第二排序是第二最近點擊過列頭的列,等等。定義一個sort.Interface的實現用在這樣的表格中。比較這個實現方式和重使用sort.Stable排序的方式。
**练习 7.8** 很多形界面提供了一个有状态的多重排序表格插件:主要的排序是最近一次点击过列头的列,第二排序是第二最近点击过列头的列,等等。定义一个sort.Interface的实现用在这样的表格中。比较这个实现方式和重使用sort.Stable排序的方式。
**練習 7.9** 使用html/template包 (§4.6) 替代printTrackstracks展示成一HTML表格。將這個解決方案用在前一個練習中,每次點擊一個列的頭部産生一HTTP請求來排序這個表格。
**练习 7.9** 使用html/template包 (§4.6) 替代printTrackstracks展示成一HTML表格。将这个解决方案用在前一个练习中,每次点击一个列的头部产生一HTTP请求来排序这个表格。
**練習 7.10** sort.Interface型也可以用在其它地方。編寫一個IsPalindrome(s sort.Interface) bool函表明序列s是否是文序列,換句話説反向排序不會改變這個序列。假如果!s.Less(i, j) && !s.Less(j, i)索引i和j上的元素相等。
**练习 7.10** sort.Interface型也可以用在其它地方。编写一个IsPalindrome(s sort.Interface) bool函表明序列s是否是文序列,换句话说反向排序不会改变这个序列。假如果!s.Less(i, j) && !s.Less(j, i)索引i和j上的元素相等。