Is it possible to change map value by key?

Unexpectedly got error while trying assign/redefine map value:

{{ $map := dict "sort" "b" "name" "tag-b" "permalink" "/tags/tag-b/" }} 
{{ $map.sort = "a" }}

produces unexpected "=" in operand and so does try with “:=”
Are maps in Hugo read only or there is a secret way to change value by key?

The only way is to use Scratch, e.g.:

{{ $s := newScratch }}
{{ $s.Set "foo" "bar" }}
{{ $map := $s.Values }}

Thank you. This method works with single map, but when it comes to my task - maps joined in slice - got same error even using Scratch:

{{ $tags := slice
    (dict "sort" "b" "name" "tag-b" "name" "Tag B" "permalink" "/tags/tag-b/" )
    (dict "sort" "c" "name" "tag-c" "name" "Tag C" "permalink" "/tags/tag-c/" )
    (dict "sort" "a" "name" "tag-a" "name" "Tag A" "permalink" "/tags/tag-a/" )
}}

{{ $s := newScratch }}
{{ $s.Set "sort" "d" }}
{{ (index $tags 0) := $s.Values }}

Again got the same error unexpected ":=" in operand

Sorry for silly question, but I don’t undestand Scratch at all. For me it looks like artifical crutch to solve problems not existing in Python, JS, PHP and other languages I usually practice.

Try:

{{ $tags = $tags | append $s.Values }}

Nope. This operation not changed target map element (first element in my case), just appended one more element:

[
map[name:Tag B permalink:/tags/tag-b/ sort:b]
map[name:Tag C permalink:/tags/tag-c/ sort:c]
map[name:Tag A permalink:/tags/tag-a/ sort:a]
map[sort:d]
]

I suppose that (like in many other languages) you can’t assign to an expression. And since there’s no way to get a reference to an array element, you’re probably out of luck here.

Maybe it helps to describe what you want to achieve in more abstract terms to find another solution?

The matter is not about “assign to expression”, but to modify existing non-const data structure. The basic instrumentary of any common language. Working example in javascript:

let map = [
{
    "displayName": "Tag B",
    "name": "tag-b",
    "permalink": "/tags/tag-b/",
    "sortCriteria": "b"
},
{
    "displayName": "Tag C",
    "name": "tag-c",
    "permalink": "/tags/tag-c/",
    "sortCriteria": "c"
},
{
    "displayName": "Tag A",
    "name": "tag-a",
    "permalink": "/tags/tag-a/",
    "sortCriteria": "a"
}
];

map[0]["sortCriteria"] = "a";

I’m just wondering about missing such feature in Hugo. And researching for workaround.

Thanks, but I knew that. I just pointed out what you were doing in your Hugo code. In my experience, it is quite pointless to compare languages, and I’m sure that Go itself permits what you want. But here we’re talking about a template language, which is apparently lacking features in comparison to others.
That’s why I was asking about your goal and musing if it might be possible to achieve it in a way that’s actually possible in Hugo.

Of course Golang permits maps updating, here is example from the net

package main
 
import "fmt"
 
func main() {
	var employee = map[string]int{"Mark": 10, "Sandy": 20}
	fmt.Println(employee) // Initial Map
 
	employee["Mark"] = 50 // Edit item
	fmt.Println(employee)
}

So I’m far away of comparing languages, just looking for instrumentary that allows me to reach the goal - process some custom structured data. My previous topic here referring to the same goal.

Thanks for confirming that.

{{ $tags := slice
  (dict "sort" "b" "name" "tag-b" "permalink" "/tags/tag-b/" )
  (dict "sort" "c" "name" "tag-c" "permalink" "/tags/tag-c/" )
  (dict "sort" "a" "name" "tag-a" "permalink" "/tags/tag-a/" )
}}

{{ $sliceIndex := 0 }}    {{/* Which item in the slice do you wish to modify? */}}
{{ $mapKey := "sort" }}   {{/* Which key do you wish to modify? */}}
{{ $newValue := "z" }}    {{/* What's the new value? */}}

{{ $s := newScratch }}
{{ range seq 0 (sub (len $tags) 1) }}
  {{ $s.Set (printf "%04d" .) (index $tags .) }}
{{ end }}
{{ $s.SetInMap (printf "%04d" $sliceIndex) $mapKey $newValue }}

{{/* Here's what the map looks like. */}}
<pre>{{ jsonify (dict "indent" "  ") $s.Values }}</pre>

{{/* Now convert the map back to a slice of maps. */}}
{{ $tags := slice }}
{{ range $s.Values }}
  {{ $tags = $tags | append . }}
{{ end }}

{{/* Here's what the slice looks like. */}}
<pre>{{ jsonify (dict "indent" "  ") $tags }}</pre>
1 Like

Some time ago I created a partial to perform slice manipulation (insert, replace, delete). Something like:

{{ $newSlice := partial "modify-slice" (dict "slice" $tags "action"="replace" "index" 2 "item" $newItem }}

This would only save you three lines of code in the example above (the last bit, where we convert the map back to a slice of maps).

1 Like

Thank you! Such way of data manipulation is a new dimension in my Hugo experience.

Regarding initial topic. Significant benefit of static site generators is that excessive and not speed/data/size optimized code runs only on local machine and not taking much more valuable web server resources. So I’ve already launch a straightforward (and not too elegant) workaround solution via intermediate array. But definitely will test your solution.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.