2013-08-11 44 views
11

Tôi gặp sự cố khi sắp xếp chuỗi theo ký tự (để kiểm tra xem hai chuỗi là đảo chữ cái, tôi muốn sắp xếp cả hai chuỗi đó và kiểm tra tính bình đẳng).Đi sắp xếp một phần của rune?

tôi có thể có được một đại diện []rune của chuỗi s như thế này:

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

Và tôi có thể sắp xếp ints như thế này

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

Nhưng rune chỉ là một bí danh cho int32 vì vậy tôi nên có thể gọi

sort.Ints(runes) 

Tuy nhiên, tôi gặp lỗi:

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

Vậy ... làm cách nào để sắp xếp một phần int32, int64 hoặc int *?

EDIT: Tôi đã nhận được rune của tôi được sắp xếp, nhưng cậu bé, điều này là xấu xí.

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

Vì vậy, về cơ bản nếu bạn có một lát bất kỳ thứ gì, bạn sẽ phải gói nó theo kiểu thực hiện sort.Interface. Tất cả những triển khai đó sẽ có cùng các đối tượng phương thức giống hệt nhau (như sort.IntSlicesort.Float64Slice). Nếu điều này thực sự xấu xí như thế nào thì tại sao họ không cung cấp các trình bao bọc WhateverSlice này trong gói sort? Việc thiếu generics bắt đầu làm tổn thương rất nặng nề. Phải có cách phân loại tốt hơn.

+2

Vâng, đó là một sự vi phạm khủng khiếp của DRY. Tôi có nghĩa là có chính xác cùng một mã nhân rộng nhiều lần như có các loại cơ bản là khá xấu. Thuật toán sắp xếp chung hoạt động trên các loại cơ bản mà không cần thêm bất kỳ khâu nào là khá nhiều điều bạn mong đợi ở bất kỳ ngôn ngữ nào. Nhưng phải dạy cho trình biên dịch cách lấy chiều dài của một lát 20 lần là không thật. – andras

+0

Bạn đang thiếu điểm hoàn toàn. Thuật toán sắp xếp chung hoạt động không chỉ cho các slice, mà còn cho _anything_ thỏa mãn 'sort.Interface'. Bây giờ, làm thế nào để bạn đề xuất để automagically nhận được 'Len' và bạn bè của _anything_ bạn biết _nothing_ về trước (tại thời gian biên dịch) ??? IOW, rant của bạn không hợp lý. – zzzz

+0

Tôi không mong đợi trình biên dịch có thể sắp xếp các trường hợp 'BucketOfFish' ra khỏi hộp. 'sort.Interface' có vẻ như là một trừu tượng tốt đẹp cho các trường hợp này (mặc dù tôi có thể muốn giữ Fishes của tôi trong các slice cũng như, thay vì một số container tùy chỉnh). Tôi chỉ tìm thấy nó lạ rằng một trường hợp sử dụng cơ bản (lát của một loại cơ bản) không được bảo hiểm bởi thư viện chuẩn. – andras

Trả lời

6

Sử dụng sort.Sort(data Interface) và triển khai sort.Interface, xem ví dụ về tài liệu gói.

Bạn không thể sử dụng runeint32int. Kiểm tra comment của 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

Tôi đã kiểm tra sort.go, và đây là những gì tôi đã làm, nhưng COME ON! Tôi có thực sự phải thực hiện RuneSlice, ByteSlice, Int32Slice, UintSlice, vv vv? Đây chỉ là 3 phương pháp giống nhau với chính xác các phương pháp tương tự! Nếu đây thực sự là cách duy nhất để sắp xếp các slice khác với các slice int và float64 thì tại sao chúng không thực hiện các kiểu WhateverSlice này trong sort.go? Tôi sẽ kết thúc việc thực hiện chúng trong utils của tôi anyway. Đây có phải là vì thiếu generics? Thôi nào, phải có cách tốt hơn. – andras

+0

@andras Đó là một câu hỏi hay. Tôi sẽ đặt nó trên StackOverflow. –

+4

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

2

Giống như một điểm so sánh, đây là những gì mọi thứ có thể trông như thế nào nếu giao diện sắp xếp hơi khác. Tức là, thay vì giao diện nằm trên vùng chứa , thì mọi thứ sẽ trông như thế nào nếu giao diện ở trên các yếu tố thay thế?

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

Ở đây, chúng ta định nghĩa một giao diện Comparable, và chúng tôi nhận loại của chúng tôi ComparableRune để thỏa mãn nó. Nhưng vì nó là một giao diện, chúng ta phải làm như đấm bốc vụng về để đi rune-ComparableRune để cử động có thể đá trong:

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

và unboxing để lấy lại rune của chúng tôi:

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

Cách tiếp cận này dường như yêu cầu chúng tôi biết cách thực hiện các kiểu nhập để chuyển qua lại giữa giao diện và loại động của giá trị. Có vẻ như chúng ta sẽ cần sử dụng nhiều phần của Go --- cơ học hơn --- so với cách tiếp cận sử dụng container làm giao diện.

+0

thanks dyoo! Điều này là hữu ích (mặc dù vẫn không thực sự có thể sử dụng :). Ít nhất tôi thấy cách bạn sẽ làm điều đó theo phong cách Java.Tuy nhiên, việc thiếu thuốc generic (một rổ táo không phải là một giỏ trái cây) làm cho giải pháp không khả thi. – andras

+0

Yup! Nhưng chúng ta hãy lưu ý về generics trong số này, ít nhất là cho bây giờ. Nếu không, câu hỏi có thể có khả năng biến thành "Tại sao không đi hỗ trợ Generics ?!", đó là một cái gì đó chúng ta không thể trả lời một cách hiệu quả. Nó sẽ rất * đẹp * nếu nó có (có thể), nhưng các giải pháp được đề xuất ở đây dường như là cách thích hợp để sử dụng thường trình 'sort.Sort' chung và cách hệ thống kiểu hiện tại của Go ảnh hưởng đến việc sử dụng nó như thế nào. – dyoo

+0

Bạn nói đúng về điều này, và tôi không ngụ ý điều này như một lời rít rền như "Tại sao không đi như ngôn ngữ X?". Tôi muốn học thành ngữ Go, nhưng phải thực hiện 'sort.Interface' cho các kiểu cơ bản thì cảm thấy kỳ lạ đến mức tôi nghĩ mình phải làm gì đó sai. Có lẽ trong thời gian tôi sẽ học cách đi và vấn đề này sẽ không làm phiền tôi nhiều :) – andras

3

Có, trên thực tế, cách mềm chung để thực hiện những gì bạn muốn.

Kiểm tra các gói sau:

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

đặc biệt là các tập tin sau đây:

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

Ví dụ về cách nó được sử dụng:

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

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

Có rất nhiều niềm vui thú vị khác các thuật toán chung được thực hiện thông qua sự phản chiếu trong gói đó.

Tất cả tín dụng đi đến @BurntSushi.

+0

Cảm ơn, điều này có vẻ hữu ích. Dường như nó thực thi an toàn loại trong suốt thời gian chạy sử dụng sự phản chiếu? (hoặc ma thuật đen, cho rằng vấn đề, như tôi không thể quấn quanh đầu của tôi xung quanh mã nguồn nào :) – andras

2

Lưu ý: Đi 1.8 sẽ giới thiệu người trợ giúp để phân loại lát.
Xem và commit 22a2bdf bởi 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 –

Các vấn đề liên quan