Сортировать кусочек руны?

У меня проблемы с сортировкой строк по символам (чтобы проверить, являются ли две строки анаграммами, я хочу отсортировать их обе и проверить на равенство).

Я могу получить []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/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.

Другие вопросы по тегам