如何比较Map的通用键并打印输出?

I have the following code which generates the following output

code:

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

}

link: https://play.golang.org/p/yM9_wWmyLY
Output:

Test=15 Test=15

I want to compare the Container1 with Container2 and if they have common key, i just want to print output only once.

Output: Test=15

How can i achieve this? Any help is appreciated?

I can think of two ways to do this:

  1. Dedup your data before passing to the template execution

    This means you can pre-process the data before passing to t.Execute to eliminate duplicates. You can do this using something like:

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

    Then you can just pass the processed data and the template itself remains virtually unchanged

  2. Add a custom function for your template

    This means you can add a normal go function that receives as many EntitiesClass as you like and returns them deduplicated (perhaps with the mechanism from option 1).

    You can even do something like:

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

For your simple example I would choose option 1, it seems easiest to leave templates very simple.

This applies some filtering logic. I'm using text/template because this code isn't using a server. It will work the same with html/template. When appending to slices of structs pointers have to be used. If you don't know why see here. func isInSlice() bool needs to be modded to your needs. This serves as an example.

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

}