如何在Go中对不同结构类型的列表进行排序

huangapple go评论74阅读模式
英文:

How to order a list of different struct types in go

问题

我只用Go工作了几天。我定义了几种不同的结构类型,每种类型都包含一个日期。

不知何故,我需要按日期顺序处理这些结构,但这种排序必须跨越多个不同的结构类型。在像Python这样的动态类型语言中,只需创建一个以日期为键的对象哈希(如果它们不唯一,则创建一个列表的哈希)。在C中,我可以使用指针或void*的联合。但是我不知道如何在Go中做到这一点。

我猜我可以保持每种类型的排序列表,并在进行操作时手动进行归并排序。看起来有点笨拙?

我读到的关于处理这种情况的方法似乎指向使用接口,但我真的不知道如何在这种情况下使用它们。

为了论证,假设我有类似以下的东西:

type A struct {
    Date string
    Info string
}

type B struct {
    Date string
    Info int
}

(实际上有更多的结构,并且它们更复杂,有多个字段),只需要按日期顺序打印它们的内容(未排序的数组)。

是否有一种方法可以将(日期,指针)对创建为非统一对象类型的列表?


根据下面的第一个建议:

package main
import "fmt"

type A struct {
    Date string
    Info string
}
func (x *A) GetDate() string {
    return x.Date
}
type B struct {
    Date string
    Info int
}
func (x *B) GetDate() string {
    return x.Date
}

type Dater interface {
    GetDate() string
}

type Daters []Dater
func (s Daters) Len() int      { return len(s) }
func (s Daters) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
type ByDate struct{ Daters }
func (s ByDate) Less(i, j int) bool {
    return s.Daters[i].GetDate() < s.Daters[j].GetDate()
}   

func main() {
    // lista and listb are just examples. They really come from elsewhere
    lista := []A{{"2012/08/01", "one"}, {"2012/08/03", "three"}}
    listb := []B{{"2012/08/02", 2}, {"2012/08/04", 4}}

    x := make([]Dater, len(lista) + len(listb))
    index := 0
    for i := range(lista) {
        x[index] = &lista[i]
        index++
    }
    for i := range(listb) {
        x[index] = &listb[i]
        index++
    }
    sort.Sort(ByDate{x})
    for _,v := range(x) {
        fmt.Printf("%#v\n", v)
    }
}

这个代码可以工作!所以基本使用接口是正确的,我开始更好地理解接口了 - 谢谢!

注意:创建x的方式相当丑陋。我看不到更简洁/更符合惯用法的方法?

英文:

I've only been working with Go for a couple of days. I have a small variety of different structure types defined, each of which contains a date.

Somehow I need to process those structures in date order, but that ordering has to span across the multiple different structure types. In a dynamically typed language like Python, it's easy to just create a hash of all the objects keyed by date (or hash of lists if they're not unique). In C, I can use unions of pointers or void*. But I'm stuck as to how do this in Go.

I guess I could keep a sorted list of each type and do a manual mergesort as I go. Seems klunky?

What I've read about handling this sort of situation seems to point to using interfaces, but I don't really see how to use them in this situation.

For the sake of argument, let's say I have something like:

type A struct {
    Date string
    Info string
}

type B struct {
    Date string
    Info int
}

(Though in practice there are more structures, and they are more complex with multiple fields), and just need to print in date order the contents of an (unsorted) array of each of them.

Is there some way to create a list (date, pointer) pairs to a non-uniform object type?


Per first suggestion below:

package main
import &quot;fmt&quot;

type A struct {
    Date string
    Info string
}
func (x *A) GetDate() string {
    return x.Date
}
type B struct {
    Date string
    Info int
}
func (x *B) GetDate() string {
    return x.Date
}

type Dater interface {
    GetDate() string
}

type Daters []Dater
func (s Daters) Len() int      { return len(s) }
func (s Daters) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
type ByDate struct{ Daters }
func (s ByDate) Less(i, j int) bool {
    return s.Daters[i].GetDate() &lt; s.Daters[j].GetDate()
}   

func main() {
    // lista and listb are just examples. They really come from elsewhere
    lista := []A{{&quot;2012/08/01&quot;, &quot;one&quot;}, {&quot;2012/08/03&quot;, &quot;three&quot;}}
    listb := []B{{&quot;2012/08/02&quot;, 2}, {&quot;2012/08/04&quot;, 4}}

    x := make([]Dater, len(lista) + len(listb))
    index := 0
    for i := range(lista) {
        x[index] = &amp;lista[i]
        index++
    }
    for i := range(listb) {
        x[index] = &amp;listb[i]
        index++
    }
    sort.Sort(ByDate{x})
    for _,v := range(x) {
        fmt.Printf(&quot;%#v\n&quot;, v)
    }
}

That works! So the basic use of interface is fine, and I'm starting to understand
interfaces a little better - thank you!

Note: The creation of x is pretty ugly. I can't see a cleaner / more idiomatic way?

答案1

得分: 3

定义一个接口(称为Dated),其中包含一个方法(称为getDate(),返回Date类型)。然后让所有的结构体(A、B、C)实现Dated接口。然后你可以定义一个[]Dated来保存你的类型值。

你可能想要检查一下"time"和"sort"包来简化实现。

英文:

Define a interface (say Dated) with a method (say getDate() that returns Date). Then have all structs (A, B, C) implementing Dated interface. Then you can define use []Dated to hold your type values.

You might want to check package 'time' and 'sort' to simplify the implementation.

答案2

得分: 0

你可以使用嵌入来实现。

你可以定义一个只包含日期的结构体,然后将其嵌入到其他结构体中。这样,你只需要实现一次GetDate()方法。而且,你还可以随时扩展Date结构体,而不需要修改其他结构体。

package main

type Dater interface {
    GetDate() string
}

type Date struct {
    Date string
}

func (d *Date) GetDate() string {
    return d.Date
}

type A struct {
    Date
    Info string
}

type B struct {
    Date
    Info []byte
}

type C struct {
    Date
    Info int32
}

现在你可以在A、B和C上调用GetDate()方法。

英文:

You might be able to use embedding.

You would define a struct that contains nothing but the date, then embed it in the others. That way, you only have to implement GetDate() once. You can also extend the Date struct at any time without modifying the other structs.

package main

type Dater interface {
    GetDate() string
}

type Date struct {
    Date string
}

func (d *Date) GetDate() string {
    return d.Date
}

type A struct {
    Date
    Info string
}

type B struct {
    Date
    Info []byte
}

type C struct {
    Date
    Info int32
}

You can now call GetDate() on A, B, and C.

huangapple
  • 本文由 发表于 2012年9月17日 10:29:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/12452502.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定