Iterate Go map get index

In order to use a revel

even

keyword in templates, I would like to get the index of the map entry when iterating with range

. Is there a way to do this? My map has the following structure:

map[string][]string

      

+3


source to share


4 answers


You cannot do this with template actions alone, but you can register a function that provides the assistance you need.

You can register a function that returns a function (a closure) that alternates between the return value when called (just like β€œodd” and β€œeven” indexes alternate):

func isEven() func() bool {
    e := false
    return func() bool {
        e = !e
        return e
    }
}

      

I named it isEven()

to avoid colliding with ravel even()

. Using it:

func main() {
    t := template.Must(template.New("").Funcs(template.FuncMap{
        "isEven": isEven,
    }).Parse(templ))

    m := map[string]string{
        "a": "A", "b": "B", "c": "C", "d": "D",
    }
    if err := t.Execute(os.Stdout, m); err != nil {
        panic(err)
    }
}

const templ = `{{$e := isEven}}
{{- range $k, $v := . -}}
    [even:{{call $e}}] key={{$k}}; value={{$v}}
{{end}}`

      

Conclusion (try it on the Go Playground ):

[even:true] key=a; value=A
[even:false] key=b; value=B
[even:true] key=c; value=C
[even:false] key=d; value=D

      

If you need different output for odd and even iterations, you can call $e

in action {{if}}

, for example:

const templ = `{{$e := isEven}}
{{- range $k, $v := . -}}
    [{{if call $e}}even{{else}}odd {{end}}] key={{$k}}; value={{$v}}
{{end}}`

      



Result of this (try it on the Go Playground ):

[even] key=a; value=A
[odd ] key=b; value=B
[even] key=c; value=C
[odd ] key=d; value=D

      

Under the hood

This is the template action:

{{$e := isEven}}

      

Creates a new template variable with a name $e

, and its value will be the result (return value) of the function call isEven()

. isEven()

returns the value of a function, a closure that has access to a local variable of the e

type bool

. When you are done {{call $e}}

, you are not calling the isEven()

Go function , but the function it returns (the closure) and saved to $e

. This closure has a reference to a local variable bool

e

, it is not "released" until the return function is available isEvent()

.

That way, whenever you do {{call $e}}

, it calls a closure that has a "has" e

type variable bool

whose value persists between calls to that $e

.

If you call it again isEvent

in the template, you will return a new function (closure) by wrapping a new instance of a local variable e

, independent of the first wrapped closure variable returned by the first call isEvent()

.

+3


source


{{range $key, $element := .Map}}
  {{$index := index .Map $key}}
{{end}}

      



0


source


Map entries have no Go index; you cannot get the index from any element. Also, every time you iterate on a map with range

, you end up with a different order - another hint of the lack of an index concept on maps.

Indexes only refer to ordered data structures (such as arrays, fragments, lists, etc.), not maps. Take a look at https://blog.golang.org/go-maps-in-action for more details.

0


source


An easy way to reach the index while walking through the map:

package main

import (
    "fmt"
)

func main() {
    mm := map[string]int{"xx" : 1, "gg" : 2}
    cnt := 0
    for a, b:= range mm{
        fmt.Println("a", a, "b",b, "c" , cnt)
        cnt++
    }
    fmt.Println("Hello, playground")
}

      

And prints:

a xx b 1 c 0
a gg b 2 c 1
Hello, playground

      

0


source







All Articles