Golang和结构数组的结构

时间:2017-05-10 13:09:06

标签: loops go struct slice

我为电影和电视节目定义了以下结构:

type Movie struct {
    ID      string `json:"id"`
    Viewers int    `json:"count"`
}
type TVShow struct {
    ID      string `json:"id"`
    Season  int    `json:"season"`
    Episode int    `json:"episode"`
    Viewers int    `json:"count"`
}

然后我有以下结构,包含几个国家的电影或电视节目:

type Movies struct {
    PenultimateMonth map[string][]Movie
    LastMonth        map[string][]Movie
}
type TVShows struct {
    PenultimateMonth map[string][]TVShow
    LastMonth        map[string][]TVShow
}

最后,我有一个包含所有内容的数据结构:

type Data struct {
    Movies  Movies
    Seasons Seasons
}

我需要做的是从倒数第二个月和上个月收集所有电影和电视节目的所有 ID。

我发现我可以使用反射,但我只是设法迭代每个Data元素而不是全部:

func GetIDs(data *Data, country string) []string {
    var ids []string

    movies := reflect.ValueOf(data.Movies).Elem()
    tvShows := reflect.ValueOf(data.TVShows).Elem()

    for i := 0; i < movies.NumField(); i++ {
        moviesSubset := movies.Field(i).Interface().(map[string][]Movie)
        for _, movie := range moviesSubset[country] {
            ids = append(ids, movie.ID)
        }
    }

    for i := 0; i < tvShows.NumField(); i++ {
        tvShowsSubset := tvShows.Field(i).Interface().(map[string][]TVShow)
        for _, tvShow := range tvShowsSubset[country] {
            ids = append(ids, tvShow.ID)
        }
    }

    return ids
}

是否可以简化GetIDs功能,以便我不需要两个单独的电影和电视节目块,但只需要一个来收集所有ID?

1 个答案:

答案 0 :(得分:0)

使用界面:

type identifiable interface {
    GetID() string
}

type identifiables interface {
    GetIDs() []string
}

你可以实现如下:

func (m Movie) GetID() string { return m.ID }

用于以多态方式收集ID。

您可以为每种类型编写它,或者让地图存储界面并实现一次。

type identifiable interface {
    GetID() string
}

type identifiables interface {
    GetIDs() []string
}

func (m Movie) GetID() string { return m.ID }

type movies []Movie
type moviesByCountry map[string]movies

func (m movies) GetIDs() (ret []string) {
    for _, movie := range m {
        ret = append(ret, movie.GetID())
    }
    return
}

func (m moviesByCountry) GetIDs() (ret []string) {
    for _, slice := range m {
        ret = append(ret, slice.GetIDs()...)
    }
    return
}

func (d Data) GetCountryIDs(country string) []string {
    return gatherIDs(d.TVShows[country], d.Movies[country])
}

func gatherIDs(collections ...identifiables) (ret []string) {
    for _, collection := range collections {
        ret = append(ret, collection.GetIDs()...)
    }
    return
}

这是working playground example

效率不高但简单且一致的恕我直言。如果这是一个问题,可以通过传入累加器切片来优化它,但我建议使用私有方法的接口去那条路。

我认为

有合理的理由
type identifiableByCountry interface {
    GetCountryIDs(string) []string
}

因为Data和地图都可以实现。

如果您更喜欢使用lambdas,您还可以使用以下内容:

type collection interface {
    walk(func(identifiable))
}

并在集合类型上实现它,将其用作

c.walk(func(o identifiable) {
    ids = append(ids, o.GetID())
})