0

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?

Peter
  • 29,454
  • 5
  • 48
  • 60
Maddy_15
  • 61
  • 5
  • 1
    nit-pick: The spelling is "Entities", and Go doesn't have classes, so that term should be avoided. – Peter Sep 29 '17 at 11:04

2 Answers2

3

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.

cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • A fun go trick is to use a `map[EntitiesClass]struct{}` because you never need to actually look at the `bool`. This saves the memory that would be used by the `bool` because using an empty `struct{}` value doesn't allocate any. https://dave.cheney.net/2014/03/25/the-empty-struct – RayfenWindspear Sep 29 '17 at 22:26
  • @RayfenWindspear That's a nice one to use when the map is large. But otherwise for small maps using bool makes for a nicer syntax when checking presence in the map. `if m[x]` vs `if _, ok := m[x]; ok` – cnicutar Oct 01 '17 at 09:20
0

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

}
reticentroot
  • 3,612
  • 2
  • 22
  • 39