Сортировать кусочек руны?
У меня проблемы с сортировкой строк по символам (чтобы проверить, являются ли две строки анаграммами, я хочу отсортировать их обе и проверить на равенство).
Я могу получить []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.IntSlice
а также sort.Float64Slice
). Если это действительно ужасно, то почему же они не предоставили эти обертки Whis бы то ни было в sort
пакет? Отсутствие дженериков начинает очень сильно болеть сейчас. Должен быть лучший способ сортировки вещей.
4 ответа
Использование sort.Sort(data Interface)
и реализовать sort.Interface
см. примеры в документации к пакету.
Вы не можете использовать rune
который int32
как int
, Проверьте комментарий int
,
int - это целочисленный тип со знаком, размер которого не менее 32 бит. Однако это отдельный тип, а не псевдоним, скажем, int32.
Примечание: Go 1.8 представит помощников для сортировки ломтиков.
Смотрите выпуск 16721 и пишите 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]
})
}
По крайней мере, с ноября 2020 года 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
Это может избавить вас от полной реализации интерфейса.
Просто для сравнения, вот как все могло бы выглядеть, если бы интерфейс сортировки был немного другим. То есть, вместо того чтобы интерфейс находился в контейнере, что бы выглядело, если бы интерфейс был вместо элементов?
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 - больше механики - чем подход, который использует контейнер в качестве интерфейса.
На самом деле существует мягкий и общий способ делать то, что вы хотите.
Проверьте следующий пакет:
особенно следующий файл:
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.