Иди, кусочек рун?
У меня возникли проблемы с сортировкой строк по символу (чтобы проверить, являются ли две строки анаграммами, я хочу их отсортировать и проверить на равенство).
Я могу получить представление []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
). Если это действительно так уродливо, это должно быть тогда, почему они не предоставили эти обертки WhateverSlice в пакете sort
? Отсутствие дженериков начинает сильно болеть сейчас. Должен быть лучший способ сортировки вещей.
Ответы
Ответ 1
Используйте sort.Sort(data Interface)
и реализуйте sort.Interface
, см. примеры документации пакетов.
Вы не можете использовать rune
, который int32
как int
. Проверьте комментарий int
.
int - это целочисленный тип со знаком, размер которого не менее 32 бит. Это но не псевдоним для, скажем, int32.
Ответ 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.
Ответ 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 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)
}
и unboxing, чтобы вернуть наши руны:
sortedRunes := make([]rune, len(msg))
for i, v := range comparables {
sortedRunes[i] = rune(v.(ComparableRune))
}
Этот подход, по-видимому, требует, чтобы мы знали, как делать машинные приемы, чтобы идти туда и обратно между интерфейсом и динамическим типом значения. Похоже, нам нужно будет использовать больше частей Go --- more mechanics --- чем подход, который использует контейнер в качестве интерфейса.
Ответ 4
Примечание. 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]
})
}