【问题标题】:How to compare Map for common keys and print the output?如何比较常用键的 Map 并打印输出?
【发布时间】:2017-09-29 10:43:13
【问题描述】:

我有以下代码生成以下输出

代码:

package main

import (
    "html/template"
    "os"
)

type EntetiesClass struct {
    Name  string
    Value int32
}

// In the template, we use rangeStruct to turn our struct values
// into a slice we can iterate over
var htmlTemplate = `{{range $index, $element := .}}
{{range $element}}{{.Name}}={{.Value}}
{{- end}}
{{- end}}`

func main() {
    data := map[string][]EntetiesClass{
            "Container1": {{"Test", 15}},
            "Container2": {{"Test", 15}},
    }

    t := template.New("t")
    t, err := t.Parse(htmlTemplate)
    if err != nil {
            panic(err)
    }

    err = t.Execute(os.Stdout, data)
    if err != nil {
            panic(err)
    }

}

链接:https://play.golang.org/p/yM9_wWmyLY
输出:

测试=15 测试=15

我想比较 Container1 和 Container2,如果它们有共同的键,我只想打印一次输出。

输出: 测试=15

我怎样才能做到这一点?任何帮助表示赞赏?

【问题讨论】:

  • nit-pick:拼写是“Entities”,Go 没有类,所以应该避免使用这个词。

标签: go


【解决方案1】:

我可以想到两种方法来做到这一点:

  1. 在传递给模板执行之前删除您的数据

    这意味着您可以在传递给t.Execute 之前对数据进行预处理,以消除重复数据。您可以使用以下方式执行此操作:

    m := map[EntitiesClass]bool{}
    for _, ... {
        m[ec] = true
        // Or maybe you want to aggregate "Container 1"
        // and "Container 2" in some way
    }
    

    然后您可以只传递处理后的数据,模板本身几乎保持不变

  2. 添加custom function for your template

    这意味着您可以添加一个普通的 go 函数,该函数接收任意数量的 EntitiesClass 并返回去重(可能使用选项 1 中的机制)。

    您甚至可以执行以下操作:

    {{if not customHaveSeenThisValueBefore }}
       ...
    {{ endif }}
    

对于您的简单示例,我会选择选项 1,让模板非常简单似乎最容易。

【讨论】:

  • 一个有趣的技巧是使用map[EntitiesClass]struct{},因为您永远不需要实际查看bool。这节省了bool 将使用的内存,因为使用空的struct{} 值不会分配任何内存。 dave.cheney.net/2014/03/25/the-empty-struct
  • @RayfenWindspear 当地图很大时,这是一个不错的选择。但是对于使用 bool 的小地图,在检查地图中的存在时会产生更好的语法。 if m[x]if _, ok := m[x]; ok
【解决方案2】:

这应用了一些过滤逻辑。我正在使用text/template,因为此代码未使用服务器。它与html/template 相同。当附加到结构切片时,必须使用指针。如果您不知道为什么,请参阅herefunc isInSlice() bool 需要根据您的需要进行修改。这是一个例子。

package main

import (
    "os"
    "text/template"
)

type Entitie struct {
    Results []*Data
}

type Data struct {
    Name  string
    Value int32
}

// Change this function to mod how to filter
func (e *Entitie) isInSlice(name string) bool {
    for _, item := range e.Results {
        if item.Name == name {
            return true
        }
    }
    return false
}

func (e *Entitie) AddData(name string, value int32) {
    if !e.isInSlice(name) {
        e.Results = append(e.Results, &Data{Name: name, Value: value})
    }
}

// In the template, we use rangeStruct to turn our struct values
// into a slice we can iterate over
var template = `
    {{range $i, $e := .Data.Results}}
        {{$e.Name}} = {{$e.Value}}
    {{end}}
    `

func main() {
    data := make(map[string]Entitie)

    var entities Entitie

    entities.AddData("test", 15)
    entities.AddData("test", 15)
    entities.AddData("test2", 15)

    t := template.New("t")
    t, err := t.Parse(template)
    if err != nil {
        panic(err)
    }

    data["Data"] = entities

    err = t.Execute(os.Stdout, data)
    if err != nil {
        panic(err)
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-04
    • 1970-01-01
    • 2022-11-15
    相关资源
    最近更新 更多