Sorting Page collection by RE match of frontmatter Param

Hello all!

I have a collection of Pages whose frontmatter includes a key like:

ages: '5-10'
ages: '10-13'
ages: '8-11'

I’d like to range over the Pages but sort it by the first number in that Param (5, 8, 10 in my example).

I was trying to use an REmatch to grab only the first digits in that string to use to sort:

{{ $post := where $.Page.Pages "Params.duration" "day" }}
{{ $sorted := sort $post (index ( ".Params.ages" | findRE "^\\d+") 0) }}

  {{ range $sorted }}
    {{ index (.Params.ages | findRE "^\\d+") 0 }} :: {{ .Params.ages }}<br/>
  {{ end }}

But the output looks like:

8 :: 8-11
10 :: 10-13
5 :: 5-8
10 :: 10-13

It seems like this should work, but I’m not sure why it’s not. Any ideas?

1 Like

I’d use min-age and max-age parameters instead. Why stuff numbers into a string if you have to convert that string later on back to numbers?

Also, you should make sure that you’re comparing numbers, not strings.

1 Like

I considered that, but I already have this key and use it in other places as-is.

I figured the logic would work the same, as the first digits in the string represent the youngest age to sort by.

1 Like

https://gohugo.io/functions/collections/sort

The second arg is a key, not a value.

1 Like

the easiest would be @chrillek s suggestion to declare an int in your frontmatter. (maybe need toml for that)

then sorting would be as easy as {{ range site.RegularPages.ByParam "min" }}

Sorting by calculated value is uncomfortable. Most of the time one would use a map, but there the keys are always strings, so printf "%04d" min is your friend for the sort order.

here’s a version using a newScratch to create a map that uses lists of pages with the same min. Each “key” holds a list of pages with the same min age taken from your ages param.

{{ $map := newScratch }}
{{ range $p := site.RegularPages }}
  {{ $min := printf "%04s" (index (split $p.Params.ages "-") 0) }}
  {{ with $map.Get $min }}
    {{ $map.Add $min $p }}
  {{ else }}
    {{ $map.Add $min (slice $p) }}
  {{ end }}
{{ end }}

to walk that map of arrays use that one

first range gets the list of pages sorted by min
second traverses the individual pages

{{ range sort $map.Values }} 
  {{ range . }}
    {{ $min := printf "%04s" (index (split .Params.ages "-") 0) }}
    {{ warnf "XP: %s -> %s -> %s " .Path $min .Params.ages }}
  {{ end }}
{{ end }}
1 Like

That worked a treat, and you and @chrillek are certainly right. At the end of day adding the frontmatter key (and adjusting other templates) makes more sense.

I did manage to get your example working nicely, so thank you very much for that!

For future searchers, I ended up with:

  {{ $daymap := newScratch }}
  {{ range $i := (where $.Page.Pages "Params.duration" "day") }}
    {{ $min := index ($i.Params.ages | findRE "^\\d+") 0  }}
    {{ with $daymap.Get $min }}
      {{ $daymap.Add $min $i }}
    {{ else }}
      {{ $daymap.Add $min (slice $i) }}
    {{ end }}
  {{ end }}

  {{ range sort $daymap.Values }}
    {{ range . }}
      {{ .Params.ages }} ==> {{ .Title }}<br>
    {{ end }}
  {{ end }}

1 Like

just found that one which which does it similar but less complicated.

depending on the number of pages the one or other may perform better.

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