LoginSignup
6
6

More than 5 years have passed since last update.

interface{} をソートする

Last updated at Posted at 2016-01-21

Slice のソート

シンプルに型アサーション (Type Assertions) を使います。

type Person struct {
    Name string
    Age  int
}

type People []Person

func (p People) Len() int           { return len(p) }
func (p People) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p People) Less(i, j int) bool { return p[i].Age < p[j].Age }

func Sort(v interface{}) interface{} {
    s, ok := v.(sort.Interface)
    if !ok {
        return v
    }
    sort.Sort(s)
    return s
}

func main() {
    people := People{{"Bob", 31}, {"John", 42}, {"Michael", 17}, {"Jenny", 26}}
    fmt.Println(people)  // [{Bob 31} {John 42} {Michael 17} {Jenny 26}]
    Sort(people)
    fmt.Println(people)  // [{Michael 17} {Jenny 26} {Bob 31} {John 42}]
}

interface{}sort.Interface を実装した Slice であると期待できる場合、この方法で十分でしょう。

入れ子になった Slice のソート

入れ子になった Slice もソートしたい場合は、構造体のフィールドと Slice のインデックスを走査します。

func Sort(v interface{}) {
    switch values := reflect.ValueOf(v); values.Kind() {
    case reflect.Slice:
        for i := 0; i < values.Len(); i++ {
            if values.Index(i).CanSet() {
                Sort(values.Index(i).Interface())
            }
        }
    case reflect.Struct:
        for i := 0; i < values.NumField(); i++ {
            if values.Field(i).CanSet() {
                Sort(values.Field(i).Interface())
            }
        }
    case reflect.Ptr:
        Sort(values.Elem().Interface())
    }
    if s, ok := v.(sort.Interface); ok {
        sort.Sort(s)
        return
    }
    switch s := v.(type) {
    case []int:
        sort.Ints(s)
    case []float64:
        sort.Float64s(s)
    case []string:
        sort.Strings(s)
    }
}

sort.Interface が実装されていないフィールドが []int, []float64, []string のいずれかだったときは sort パッケージに用意されているデフォルト実装でソートを行うようにしています。

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6