英文:
Go sort a slice of runes?
问题
我遇到了一个问题,需要按字符对字符串进行排序(为了检查两个字符串是否为变位词,我想要对它们进行排序,并检查是否相等)。
我可以这样将字符串s
转换为[]rune
表示:
runes := make([]rune, len(s))
copy(runes, []rune(s))
而且我可以这样对整数进行排序:
someInts := []int{5, 2, 6, 3, 1, 4} // 未排序
sort.Ints(someInts)
但是,rune
只是int32
的别名,所以我应该能够调用:
sort.Ints(runes)
然而,我得到了错误信息:
cannot use runes (type []rune) as type []int in function argument
那么...我该如何对int32
、int64
或int*
的切片进行排序呢?
编辑:我确实对我的runes
进行了排序,但是,这真的很丑陋。
type RuneSlice []rune
func (p RuneSlice) Len() int { return len(p) }
func (p RuneSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p RuneSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func sorted(s string) string {
runes := []rune(s)
sort.Sort(RuneSlice(runes))
return string(runes)
}
所以,基本上,如果你有一个任意类型的切片,你将不得不将其包装在一个实现了sort.Interface
接口的类型中。所有这些实现将具有完全相同的方法体(例如sort.IntSlice
和sort.Float64Slice
)。如果这确实是这么丑陋的话,那为什么他们没有在sort
包中提供这些WhateverSlice
的包装器呢?泛型的缺失现在开始非常痛苦了。肯定有更好的排序方法。
英文:
I'm having trouble sorting strings by character (to check whether two strings are anagrams, I want to sort both of them, and check for equality).
I can get a []rune
representation of the string s
like this:
runes := make([]rune, len(s))
copy(runes, []rune(s))
And I can sort ints like this
someInts := []int{5, 2, 6, 3, 1, 4} // unsorted
sort.Ints(someInts)
But rune
is just an alias for int32
so I should be able to call
sort.Ints(runes)
However, I get the error:
cannot use runes (type []rune) as type []int in function argument
So... how do I sort a slice of int32, int64, or int*?
EDIT: I did get my runes sorted, but boy, this is ugly.
type RuneSlice []rune
func (p RuneSlice) Len() int { return len(p) }
func (p RuneSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p RuneSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func sorted(s string) string {
runes := []rune(s)
sort.Sort(RuneSlice(runes))
return string(runes)
}
So basically if you have a slice of whatever, you'll have to wrap it in a type that implements sort.Interface
. All those implementations will have the exact same method bodies (like sort.IntSlice
and sort.Float64Slice
). If this is really how ugly this has to be then why didn't they provide these WhateverSlice wrappers in the sort
package? The lack of generics start to hurt very badly now. There must be a better way of sorting things.
答案1
得分: 7
使用sort.Sort(data Interface)
并实现sort.Interface
,请参考包文档中的示例。
你不能将rune
(int32
)作为int
使用。请查看int的注释。
> int是一个至少有32位大小的有符号整数类型。然而,它是一个独立的类型,而不是int32的别名。
英文:
Use sort.Sort(data Interface)
and implement sort.Interface
, see the examples on package documentation.
You cannot use rune
which is int32
as int
. Check the comment of int
.
> int is a signed integer type that is at least 32 bits in size. It is a
> distinct type, however, and not an alias for, say, int32.
答案2
得分: 5
注意:Go 1.8将引入用于对切片进行排序的辅助函数。
参见问题16721和提交22a2bdf,由Brad Fitzpatrick完成。
var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
func TestSlice(t *testing.T) {
data := strings
Slice(data[:], func(i, j int) bool {
return data[i] < data[j]
})
}
英文:
Note: Go 1.8 will introduce helpers for sorting slices.
See issue 16721 and commit 22a2bdf by Brad Fitzpatrick
var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
func TestSlice(t *testing.T) {
data := strings
Slice(data[:], func(i, j int) bool {
return data[i] < data[j]
})
}
答案3
得分: 3
作为比较的一点,如果排序接口稍有不同,情况可能会如何呢?也就是说,如果接口不是在容器上,而是在元素上,会是什么样子呢?
package main
import (
"fmt"
"sort"
)
type Comparable interface {
LessThan(Comparable) bool
}
type ComparableSlice []Comparable
func (c ComparableSlice) Len() int {
return len(c)
}
func (c ComparableSlice) Less(i, j int) bool {
return c[i].LessThan(c[j])
}
func (c ComparableSlice) Swap(i, j int) {
c[i], c[j] = c[j], c[i]
}
func SortComparables(elts []Comparable) {
sort.Sort(ComparableSlice(elts))
}
//////////////////////////////////////////////////////////////////////
// 让我们尝试使用这个:
type ComparableRune rune
func (r1 ComparableRune) LessThan(o Comparable) bool {
return r1 < o.(ComparableRune)
}
func main() {
msg := "Hello world!"
comparables := make(ComparableSlice, len(msg))
for i, v := range msg {
comparables[i] = ComparableRune(v)
}
SortComparables(comparables)
sortedRunes := make([]rune, len(msg))
for i, v := range comparables {
sortedRunes[i] = rune(v.(ComparableRune))
}
fmt.Printf("result: %#v\n", string(sortedRunes))
}
在这里,我们定义了一个Comparable
接口,并使我们的类型ComparableRune
满足它。但由于它是一个接口,我们必须进行笨拙的装箱,从rune
转换为ComparableRune
,以便动态分派可以启动:
comparables := make(ComparableSlice, len(msg))
for i, v := range msg {
comparables[i] = ComparableRune(v)
}
并进行拆箱以恢复我们的符文:
sortedRunes := make([]rune, len(msg))
for i, v := range comparables {
sortedRunes[i] = rune(v.(ComparableRune))
}
这种方法似乎要求我们知道如何进行类型转换,以在接口和值的动态类型之间来回转换。与将容器作为接口的方法相比,似乎需要使用更多的Go语言机制。
英文:
Just as a point of comparison, here's what things might look like if the sort interface were slightly different. That is, rather than the interface being on the container, what would things look like if the interface were on the elements instead?
package main
import (
"fmt"
"sort"
)
type Comparable interface {
LessThan(Comparable) bool
}
type ComparableSlice []Comparable
func (c ComparableSlice) Len() int {
return len(c)
}
func (c ComparableSlice) Less(i, j int) bool {
return c[i].LessThan(c[j])
}
func (c ComparableSlice) Swap(i, j int) {
c[i], c[j] = c[j], c[i]
}
func SortComparables(elts []Comparable) {
sort.Sort(ComparableSlice(elts))
}
//////////////////////////////////////////////////////////////////////
// Let's try using this:
type ComparableRune rune
func (r1 ComparableRune) LessThan(o Comparable) bool {
return r1 < o.(ComparableRune)
}
func main() {
msg := "Hello world!"
comparables := make(ComparableSlice, len(msg))
for i, v := range msg {
comparables[i] = ComparableRune(v)
}
SortComparables(comparables)
sortedRunes := make([]rune, len(msg))
for i, v := range comparables {
sortedRunes[i] = rune(v.(ComparableRune))
}
fmt.Printf("result: %#v\n", string(sortedRunes))
}
Here, we define a Comparable
interface, and we get our type ComparableRune
to satisfy it. But because it's an interface, we've got to do the awkward boxing to go from rune
to ComparableRune
so that dynamic dispatch can kick in:
comparables := make(ComparableSlice, len(msg))
for i, v := range msg {
comparables[i] = ComparableRune(v)
}
and unboxing to get back our runes:
sortedRunes := make([]rune, len(msg))
for i, v := range comparables {
sortedRunes[i] = rune(v.(ComparableRune))
}
This approach appears to require us to know how to do typecasts to go back and forth between the interface and the dynamic type of the value. It seems like we would need to use more parts of Go---more mechanics---than the approach that uses the container as the interface.
答案4
得分: 3
截至2020年11月,https://golang.org/pkg/sort/ 提供了使用作为闭包传递的自定义Less函数的选项。下面的代码具有所需的效果:
package main
import (
"fmt"
"sort"
)
func main() {
s1 := "eidbaooo"
runeSlice := []rune(s1)
fmt.Println(string(runeSlice))
sort.Slice(runeSlice, func(i, j int) bool {
return runeSlice[i] < runeSlice[j]
})
fmt.Println(string(runeSlice))
}
输出:
eidbaooo
abdeiooo
这样可以避免完整的接口实现。
英文:
As of November 2020 at least, https://golang.org/pkg/sort/ offers to use a custom Less function passed as a closure. The code below has the desired effect:
package main
import (
"fmt"
"sort"
)
func main() {
s1 := "eidbaooo"
runeSlice := []rune(s1)
fmt.Println(string(runeSlice))
sort.Slice(runeSlice, func(i, j int) bool {
return runeSlice[i] < runeSlice[j]
})
fmt.Println(string(runeSlice))
}
Output:
eidbaooo
abdeiooo
This can spare you the full interface implementation.
答案5
得分: 2
实际上,有一种“软通用”的方法可以实现你想要的功能。
请查看以下软件包:
特别是以下文件:
https://github.com/BurntSushi/ty/blob/master/fun/sort_test.go
下面是使用示例:
tosort := []int{10, 3, 5, 1, 15, 6}
fun.Sort(func(a, b int) bool {
return b < a
}, tosort)
该软件包中还实现了许多其他有趣的通用算法,通过反射来实现。
所有的功劳归功于@BurntSushi。
英文:
There is, in fact a soft-generic way to do what you want.
Check out the following package:
> https://github.com/BurntSushi/ty/tree/master/fun
especially the following file:
> https://github.com/BurntSushi/ty/blob/master/fun/sort_test.go
Example of how it is used:
tosort := []int{10, 3, 5, 1, 15, 6}
fun.Sort(func(a, b int) bool {
return b < a
}, tosort)
There are lots of other interesting fun generic algorithms implemented through reflection in that package.
All credits go to @BurntSushi.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论