如果我在圍棋結構數組/片,並想用那種包在我看來,我需要實現整個排序界面,包含3種方法對它們進行排序:轉:有沒有辦法避免執行完整的sort.Interface切片的結構?
- 萊恩
- 交換
- 少
看來,萊恩和交換應該始終有相同的實現無論結構類型是在數組中。
有沒有辦法避免每次都有Len和Swap實現,或者這只是Go中缺少泛型的一個侷限?
如果我在圍棋結構數組/片,並想用那種包在我看來,我需要實現整個排序界面,包含3種方法對它們進行排序:轉:有沒有辦法避免執行完整的sort.Interface切片的結構?
看來,萊恩和交換應該始終有相同的實現無論結構類型是在數組中。
有沒有辦法避免每次都有Len和Swap實現,或者這只是Go中缺少泛型的一個侷限?
你自己的回答是對的。對於數組或切片,Len()和Swap()的實現很簡單。像len()Go可以在這裏提供一個本地swap()。但是現在使用的接口也可以用於更復雜的數據結構,如BTrees。它仍然允許Sort()函數的工作(就像我的並行快速排序,它使用相同的排序接口)。
如果您要在同一個片類型上執行多個不同的比較操作,則可以使用嵌入來避免每次重新定義Len和Swap。您也可以使用這種技術爲排序添加參數,例如根據某個運行時間值來反向排序或不排序。
例如
package main
import (
"sort"
)
type T struct {
Foo int
Bar int
}
// TVector is our basic vector type.
type TVector []T
func (v TVector) Len() int {
return len(v)
}
func (v TVector) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
// default comparison.
func (v TVector) Less(i, j int) bool {
return v[i].Foo < v[j].Foo
}
// TVectorBarOrdered embeds TVector and overrides
// its Less method so that it is ordered by the Bar field.
type TVectorBarOrdered struct {
TVector
}
func (v TVectorBarOrdered) Less(i, j int) bool {
return v.TVector[i].Bar < v.TVector[j].Bar
}
// TVectorArbitraryOrdered sorts in normal or reversed
// order depending on the order of its Reversed field.
type TVectorArbitraryOrdered struct {
Reversed bool
TVector
}
func (v TVectorArbitraryOrdered) Less(i, j int) bool {
if v.Reversed {
i, j = j, i
}
return v.TVector[i].Foo < v.TVector[j].Foo
}
func main() {
v := []T{{1, 3}, {0, 6}, {3, 2}, {8, 7}}
sort.Sort(TVector(v))
sort.Sort(TVectorBarOrdered{v})
sort.Sort(TVectorArbitraryOrdered{true, v})
}
儘管這是一個老問題,我想指出 的github.com/bradfitz/slice
包。 但作爲一個例子或只是一個概念證明,我會不推薦這實際使用(它的記錄與單詞「毛」):
它採用毛,低級別的操作,以方便用較少的函數對任意片進行排序,而不用Len和Swap操作定義新類型。
在實際的代碼,我發現它完全微不足道的,快速的,短暫的,可讀的,和非分心,只是這樣做:
type points []point
func (p []points) Len() int { return len(p) }
func (p []points) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p []points) Less(i, j int) bool {
// custom, often multi-line, comparison code here
}
這裏gofmt
堅持的type
之間的空行func
行 但它沒有問題, 多個單行函數沒有空行 ,它很好地排列函數體。 我發現這是一個很好的可讀的緊湊形式這樣的事情。
至於您的評論說:
看來,萊恩和交換應該始終有相同的實現無論結構的類型是在[片段]
只是一週我需要,需要像一個簡單的變形例的那種保持對元素的切片一起(用於輸入到strings.NewReplacer
):
type pairByLen []string
func (p pairByLen) Len() int { return len(p)/2 }
func (p pairByLen) Less(i, j int) bool { return len(p[i*2]) > len(p[j*2]) }
func (p pairByLen) Swap(i, j int) {
p[i*2], p[j*2] = p[j*2], p[i*2]
p[i*2+1], p[j*2+1] = p[j*2+1], p[i*2+1]
}
這不受像github.com/bradfitz/slice
中那樣的接口的支持。 再一次,我覺得這個佈局簡單,緊湊並且可讀。 雖然(在這種情況下可能更多),但其他人可能會不同意。
如果要排序的切片(對此萊恩和交換總是有相同的實現),排序包現在擁有,只需要較少的實現的功能:
非常有趣。我想知道如何在同一個切片類型上使用多種排序。 – 2011-02-28 20:02:33