1

My problem: I have a map[string]Type which I want to iterate over in a template maintaining the random ordering behaviour of the wider language.

The Go template library states here https://golang.org/pkg/text/template/#hdr-Actions that :

If the value is a map and the keys are of basic type with a defined order ("comparable"), the elements will be visited in sorted key order.

I know I can work around this by declaring a separate []string of the keys in the initial map, then iterate over this, i.e.:

data := map[string]DummyStruct{}
data["Windward"] = DummyStruct{"Windward", 15}
data["Phlebas"] = DummyStruct{"Phlebas", 3}
data["Art"] = DummyStruct{"Art", 3}
i := 0
indices := make([]string, len(data))
for name, value := range data {
        fmt.Printf("%v, %v\n", name, value)
    indices[i] = name
    i ++
}

however I was hoping for this being a fully native, supported feature of the templating library to match the behaviour across the wider language, however it doesn't seem to be supported at all.

See the Playground here for a full example: https://play.golang.org/p/1oTI56G5pr9

gjtempleton
  • 783
  • 7
  • 16
  • You might find my answer to this question useful https://stackoverflow.com/questions/52469714/how-to-prevent-a-map-from-sorting/52470170#52470170 – Vorsprung Oct 23 '18 at 14:35
  • 4
    _"I have a map[string]Type which I want to iterate over in a template in order (i.e. maintain the existing ordering)."_ There is no "existing" order, maps are unordered. If you iterate over the map in Go, order will be random. See [Why can't Go iterate maps in insertion order?](https://stackoverflow.com/questions/28930416/why-cant-go-iterate-maps-in-insertion-order/28931555#28931555); and [Map in order range loop](https://stackoverflow.com/questions/39450120/map-in-order-range-loop/39450454#39450454). – icza Oct 23 '18 at 14:38
  • The reason for "entirely unordered iteration over the map as when using range in the wider language" is that maps are inherently unordered. Templates cannot do anything to change that fact. – Adrian Oct 23 '18 at 14:40
  • 1
    Sorry, clarified my wording slightly to make clear that I was hoping to use the unordered behaviour, not the ordering that the template package's range function imposes. – gjtempleton Oct 23 '18 at 14:41
  • What problem are you trying to solve? – Emile Pels Oct 23 '18 at 15:44
  • Unfortunately for you that is how the template engine seems to be [implemented](https://github.com/golang/go/blob/master/src/text/template/exec.go#L361-L369) so you'll have to populate a slice in the order given by the map-range (you could do this in-template using a custom "map_to_slice" func). Alternatively you could, inside the template, pass the map to a custom func that returns a channel and range over that, to achieve a more on-the-fly feeling (e.g. https://play.golang.org/p/r9HWD2XC8h2). – mkopriva Oct 23 '18 at 17:58
  • 1
    Thank @mkopriva . That pretty much covers what I ended up doing. For the wider context, I was trying to solve this issue: https://github.com/jcmoraisjr/haproxy-ingress/issues/240 – gjtempleton Oct 25 '18 at 12:28

0 Answers0