23

我无法按字符对字符串进行排序(要检查两个字符串是否是字谜,我想对它们进行排序,并检查是否相等)。

我可以像这样得到[]rune字符串的表示s

runes := make([]rune, len(s)) 
copy(runes, []rune(s))

我可以像这样对整数进行排序

someInts := []int{5, 2, 6, 3, 1, 4} // unsorted
sort.Ints(someInts)

但这rune只是一个别名,int32所以我应该可以打电话

sort.Ints(runes) 

但是,我收到错误:

cannot use runes (type []rune) as type []int in function argument

那么...如何对 int32、int64 或 int* 的切片进行排序?

编辑:我确实整理了我的符文,但是男孩,这很难看。

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.IntSlicesort.Float64Slice)。如果这真的是多么丑陋,那么他们为什么不在包中提供这些 WhatSlice 包装器sort呢?缺乏仿制药现在开始受到非常严重的伤害。必须有更好的方法来分类事物。

4

5 回答 5

8

使用sort.Sort(data Interface)和实现sort.Interface,请参阅包文档中的示例。

您不能使用runewhich is int32as int。检查评论int。_

int 是一个有符号整数类型,大小至少为 32 位。然而,它是一种独特的类型,而不是 int32 的别名。

于 2013-08-11T11:12:44.537 回答
4

注意:Go 1.8 将引入用于排序切片的助手
请参阅问题 16721提交Brad Fitzpatrick的22a2bdf

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]
    })
}
于 2016-10-04T20:08:59.230 回答
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))
}

//////////////////////////////////////////////////////////////////////
// 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))
}

在这里,我们定义了一个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 的更多部分——更多的机制——而不是使用容器作为接口的方法。

于 2013-08-11T19:57:38.257 回答
2

事实上,有一种软通用的方式来做你想做的事。

查看以下软件包:

https://github.com/BurntSushi/ty/tree/master/fun

特别是以下文件:

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

于 2013-08-12T10:10:14.203 回答
2

至少截至 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

这可以为您节省完整的接口实现。

于 2020-11-25T21:51:44.447 回答