2013-08-11 16 views
11

Mam problem z sortowaniem ciągów znaków według znaków (aby sprawdzić, czy dwa ciągi są anagramami, chcę je posortować i sprawdzić równość).Czy sortujesz kawałki run?

mogę uzyskać []rune reprezentację ciąg s tak:

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

I mogę posortować ints jak to

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

Ale rune tylko aliasem int32 więc powinienem być można zadzwonić pod numer

sort.Ints(runes) 

Jednakże pojawia się błąd:

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

Więc ... Jak sortować plasterek Int32, Int64 lub int *?

EDIT: Zrobiłem moje runy posortowane, ale chłopcze, to jest brzydkie.

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

Więc w zasadzie, jeśli masz kawałek cokolwiek, trzeba zawinąć go w typie, który implementuje sort.Interface. Wszystkie te implementacje będą miały dokładnie takie same ciała metod (jak sort.IntSlice i sort.Float64Slice). Jeśli tak naprawdę to musi być brzydkie, dlaczego nie dostarczyły one owijaczy WhateverSlice w pakiecie sort? Brak leków generycznych zaczyna teraz bardzo mocno boleć. Musi istnieć lepszy sposób sortowania rzeczy.

+2

Tak, to jest przerażające naruszenie suche. Chodzi o to, że posiadanie tego samego kodu powielanego tyle razy, ile jest podstawowych typów, jest całkiem złe. Ogólne algorytmy sortowania, które działają na podstawowych typach bez dodatkowych ściegów, są prawie takie, jakich można się spodziewać w KAŻDYM języku. Ale nauczenie kompilatora, jak uzyskać 20-krotny odcinek, jest po prostu nierealne. – andras

+0

Tęsknisz za tym punktem. Ogólny algorytm sortowania działa nie tylko dla wycinków, ale dla _okolwiek_ spełniających 'sort.Interface'. Teraz, w jaki sposób proponuje się automagicznie uzyskać 'Len' i przyjaciół z _nie_ rzeczy_, o których nie wiesz nic wcześniej (podczas kompilacji) ??? IOW, twój rant nie jest racjonalny. – zzzz

+0

Nie oczekuję, że kompilator będzie mógł sortować instancje "BucketOfFish" po wyjęciu z pudełka. "sort.Interface" wydaje się być ładną abstrakcją dla tych przypadków (chociaż prawdopodobnie chcę zachować moje ryby również w plasterkach, zamiast jakiegoś niestandardowego kontenera). Po prostu dziwne, że taki podstawowy przypadek użycia (kawałek podstawowego typu) nie jest objęty standardową biblioteką. – andras

Odpowiedz

6

Użyj sort.Sort(data Interface) i zaimplementuj sort.Interface, zobacz przykłady na dokumentacji pakietu.

Nie można użyć rune, który jest int32 jako int. Sprawdź comment z 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.

+1

Sprawdziłem sort.go, i to właśnie zrobiłem, ale CHODZI O! Czy naprawdę muszę wdrożyć RuneSlice, ByteSlice, Int32Slice, UintSlice itp.? Są to te same 3 metody z dokładnie tymi samymi ciałami metod! Jeśli jest to naprawdę jedyny sposób sortowania plasterków innych niż plasterki int i float64, dlaczego nie wdrożyły one tych typów WhateverSlice w sort.go? W każdym razie skończę je implementować w moich narzędziach. Czy to z powodu braku leków generycznych? Chodź, musi być lepszy sposób. – andras

+0

@andras To jest dobre pytanie. Wrzuciłbym go do StackOverflow. –

+4

@andras: Zobacz http://godoc.org/github.com/cznic/sortutil#RuneSlice – zzzz

2

Oto, co może wyglądać, jeśli interfejs sortowania był nieco inny. To znaczy, zamiast interfejsu znajdującego się na pojemniku , co by wyglądało, gdyby interfejs był zamiast tego na elementach ?

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

Tutaj definiujemy interfejs Comparable, a my dostajemy nasz typ ComparableRune by go zadowolić. Ale ponieważ jest to interfejs, musimy zrobić niezręczną boks jechać z rune do ComparableRune tak że dynamiczny wysyłka może kopać w:

comparables := make(ComparableSlice, len(msg)) 
    for i, v := range msg { 
     comparables[i] = ComparableRune(v) 
    } 

i unboxing wrócić nasze runy:

sortedRunes := make([]rune, len(msg)) 
    for i, v := range comparables { 
     sortedRunes[i] = rune(v.(ComparableRune)) 
    } 

To podejście wydaje się wymagać od nas umiejętności wykonywania typowań danych w celu przechodzenia między interfejsem a dynamicznym typem wartości. Wygląda na to, że potrzebowalibyśmy więcej części Go --- więcej mechaniki --- niż podejście, które wykorzystuje kontener jako interfejs.

+0

dzięki dyoo! Jest to pomocne (choć nadal nie jest właściwie użyteczne :). Przynajmniej widzę, jak zrobiłbyś to w stylu Java.Jednak brak leków generycznych (kosz jabłek nie jest koszem owoców) sprawia, że ​​rozwiązanie jest niewykonalne. – andras

+0

Yup! Ale zachowajmy na ten temat uwagę na temat generycznych, przynajmniej na razie. W przeciwnym razie pytanie może zostać przeniesione na pytanie "Dlaczego program Go nie obsługuje generycznych ?!", na co nie możemy skutecznie odpowiedzieć. Byłoby to bardzo * miłe * gdyby tak (może), ale proponowane rozwiązania tutaj wydają się być właściwym sposobem na użycie bardzo ogólnej rutyny "sort.Sort" i sposobu, w jaki obecny system typu Go wpływa na jego użycie. – dyoo

+0

Masz rację co do tego, a ja nie miałem na myśli tego jako rantu typu: "Dlaczego nie jest tak jak język X?". Chciałbym nauczyć się idiomatycznego Go, ale wprowadzenie "sort.Interface" dla podstawowych typów było tak dziwne, że myślałem, że muszę zrobić coś złego. Może z czasem nauczę się Go i ten problem mi nie przeszkadza :) – andras

3

Istnieje, w pewnym sensie, miękki generyczny sposób robienia tego, co chcesz.

Sprawdź następujący pakiet:

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

zwłaszcza następujący plik:

https://github.com/BurntSushi/ty/blob/master/fun/sort_test.go

Przykład tego, jak jest on używany:

tosort := []int{10, 3, 5, 1, 15, 6} 

fun.Sort(func(a, b int) bool { 
    return b < a 
}, tosort) 

Istnieje wiele innych ciekawych zabawy ogólne algorytmy zaimplementowane poprzez odbicie w tym pakiecie.

Wszystkie kredyty idą do @BurntSushi.

+0

Dzięki, to wygląda na użyteczne. Wydaje się, że wymusza on bezpieczeństwo typu w czasie działania za pomocą odbicia? (lub czarna magia, bo nie mogę jeszcze owinąć głowy kodem źródłowym :) – andras

2

Uwaga: Przejdź 1.8, aby wprowadzić pomocników do sortowania plasterków.
Zobacz i commit 22a2bdf przez 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] 
    }) 
} 
+0

https://beta.golang.org/pkg/sort/#Slice –