Use `apply` as a "map()" equivalent

I wonder if there is an easy way to use apply to build an array of say the “.Title” of given pages or other parameter from an array of pages other than by creating a dedicated returning partial.

It seems that apply could take any kind of “dynamic” parameter, but so far, I was only able to pass the dot as “.” as argument. For example:

{{ $tags := apply site.RegularPages "index" ".Params" "tags" }}

The above will not work, as index will try and evaluate the sring “.Params” instead of the .Params of the given entry.

But the following:

{{ $entries := slice
	(dict
		"name" "Peter"
	)
	(dict
		"name" "John"
	)
	(dict
		"name" "Harry"
	)
}}
{{ with apply $entries "index" "." "name" }}
	{{ range . }}
		{{ warnf "%#v" . }}
	{{ end }}
{{ end }}

Will work, as “.” is taken for what it is, a map.

Is there something I am missing? This might not seem critical, but we’re often in a position where we have to do more gymnastic to isolate the key of an entry like so which I would suspect might be resource costful for hundreds of entries:

{{ $entry_names := slice }}
{{ range .Pages }}
	{{ $entry_names = $entry_names | append .Title }}
{{ end }}
1 Like

The underlying limitation seems to be:

{{ index .Page "Title" }} --> error calling index: can’t index item of type hugolib.pageState

So here’s an ugly workaround that throws a .Path warning:

{{ apply (site.RegularPages | jsonify | unmarshal) "index" "." "Title" }}

Or to get an array of arrays for the tags:

{{ apply (site.RegularPages | jsonify | unmarshal) "index" "." "Params" "tags" }}
1 Like

Yes that’s pretty smart… I’ll try that! Thanks!

I might a related grievance with apply too.
I use patterns to generate sequences:

  {{- $init := dict
"NNVR" "𝟏→[𝟐](V)→[𝟑](R)"
"NVRN" "𝟏→[𝟐](R)→𝟑"
"NRNV" "[𝟏](R)→𝟐→[𝟑](R)"
"RNVN" "𝟏→[𝟐](R)→𝟑"
"NVVV" "𝟏→[𝟐](V)→[𝟑](R)"
"N4" "𝟏→𝟐→𝟑"
-}}

and in some cases I need to remove all markup. Avoids maintaining several parallel lists. So I would use (replaceRE (|[|)|]|R|V "" (index $body_patterns .P)) so the function applid to a string after the substitution. To simplify the code it would make sense to apply the plainification (which concerns only segments, so I can’t run plainify on the whole result) on the map itself.
Naturally replace refuses, but I had hope apply, which references “collections” and not strings, would accept, but it doesn’t.

error calling apply: can’t apply over map

Is there a generic way to apply a function on the elements of a map?
Since we can’t rename a key, how apply should behave should be obvious.

Just make a copy:

{{ $keyValuePairs := dict "a" 6 "b" 7 }}
{{ $m := dict }}
{{ range $k, $v := $keyValuePairs }}
  {{ $m = merge $m (dict $k (div 42 $v)) }}
{{ end }}

In the above, div 42 $v is the value transformation.

A script language should spare us that kind of boilerplate code, especially when a function that should by all means logically apply (pun intended) already exists. I know I can make a copy… But it’s bummer. I’mma make a request.

This is a map. Think about it.

{
   "a": [
      {
         "age": 30,
         "name": "Alice"
      },
      {
         "age": 25,
         "name": "Bob"
      },
      {
         "age": 35,
         "name": "Charlie"
      }
   ],
   "b": {
      "bar": [
         true,
         "x",
         21
      ],
      "foo": [
         6,
         7,
         42
      ]
   },
   "c": true,
   "d": {
      "Date": "2023-01-01T00:00:00Z",
      "Aliases": [],
      "BundleType": "",
      "Draft": false,
      "Keywords": null,
      "Sitemap": {
         "ChangeFreq": "",
         "Priority": -1,
         "Filename": "sitemap.xml",
         "Disable": false
      },
      "Weight": 0
   }
}
1 Like

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