Explicit positioning of elements within a slice

If I have a slice of lets say countries:
United States, Brazil, Georgia, Ghana, China, Australia, Canada,

They are in a variable: $countries

Let us say I wanted to move Ghana from position 4 to position 1.

I know I can use Index to GET the value, but for the life of me I can’t resolve how to reposition it.

(something equivalent to Javscript Splice?)

There is not a built-in function or method to handle this for you. I came up with a couple of slice manipulation partials last year.

Example
{{ $countries := slice
  "United States"
  "Brazil"
  "Georgia"
  "Ghana"
  "China"
  "Australia"
  "Canada"
}}

{{ $item := "Ghana" }}

{{/* Remove item from slice. */}}
{{ $matchingIndices := partial "functions/find-in-slice.html" (dict "slice" $countries "item" $item) }}
{{ range $matchingIndices }}
  {{ $countries = partial "functions/modify-slice.html" (dict "slice" $countries "action" "delete" "index" .) }}
{{ end }}

{{/* Insert item at beginning of slice (index 0). */}}
{{ $countries = partial "functions/modify-slice.html" (dict "slice" $countries "action" "insert" "index" 0 "item" $item) }}

layouts/partials/functions/find-in-slice.html
{{/*

Usage:

  {{ partial "functions/find-in-slice.html" (dict "slice" $s "item" $a) }}

  Returns a slice of integers, each representing the zero-based index of the
  matching items in the slice. If there are no matches, returns an empty slice.

Notes:

  If you do not provide an item to search for, an empty slice is returned.

*/}}

{{ $ns := "functions" }}
{{ $partial := "find-in-slice.html" }}

{{ $pre := printf "[partial: %s/%s]" $ns $partial }}
{{ $msg1 := printf "%s The 'slice' argument is missing or it is an empty slice." $pre }}
{{ $msg2 := printf "%s The 'slice' argument is not a slice." $pre }}

{{ $slice := .slice }}
{{ $item := .item }}

{{ $newSlice := slice }}

{{ if $slice }}
  {{ if reflect.IsSlice $slice }}
    {{ range $k, $v := $slice }}
      {{ if eq $v $item }}
        {{ $newSlice = $newSlice | append $k }}
      {{ end }}
    {{ end }}
  {{ else }}
    {{ errorf $msg2 }}
  {{ end }}
{{ else }}
  {{ errorf $msg1 }}
{{ end }}

{{ return $newSlice}}

layouts/partials/functions/modify-slice.html
{{/*

Usage:

  {{ partial "functions/modify-slice.html" (dict "slice" $s "action" "delete" "index" 2) }}
  {{ partial "functions/modify-slice.html" (dict "slice" $s "action" "insert" "index" 2 "item" $a) }}
  {{ partial "functions/modify-slice.html" (dict "slice" $s "action" "replace" "index" 2 "item" $a) }}

  delete 0  --> deletes the first item
  delete 1  --> deletes the second item
  delete -2 --> deletes the second to last item
  delete -1 --> deletes the last item

  insert 0  --> inserts new element before the first item
  insert 1  --> inserts new element before the second item
  insert 2  --> inserts new element before the third item
  insert -2 --> inserts new element before the last item
  insert -1 --> inserts new element after the last item

  replace 0  --> replaces the first item
  replace 1  --> replaces the second item
  replace -2 --> replaces the second to last item
  replace -1 --> replaces the last item

Notes:

  If you insert without providing an item to insert, the slice will remain
  unchanged.

  If you replace without providing a replacement item, the item will be
  deleted.

*/}}

{{ $ns := "functions" }}
{{ $partial := "modify-slice.html" }}

{{ $pre := printf "[partial: %s/%s]" $ns $partial }}
{{ $msg6 := printf "%s The 'index' argument is out of range." $pre }}
{{ $msg5 := printf "%s The 'index' argument is either missing or it is not an integer." $pre }}
{{ $msg4 := printf "%s The 'action' argument must be 'delete', 'insert', or 'replace'." $pre }}
{{ $msg3 := printf "%s The 'action' argument is missing, false, or zero." $pre }}
{{ $msg2 := printf "%s The 'slice' argument is not a slice." $pre }}
{{ $msg1 := printf "%s The 'slice' argument is missing or it is an empty slice." $pre }}

{{ $slice := .slice }}
{{ $action := .action }}
{{ $index := .index }}
{{ $item := .item }}

{{ $length := 0 }}
{{ $error := false }}
{{ $firstPart := slice }}
{{ $lastPart := slice }}
{{ $newSlice := slice }}

{{ if $slice }}
  {{ if reflect.IsSlice $slice }}
    {{ $length = len $slice }}
    {{ if $action }}
      {{ if in (slice "delete" "insert" "replace") $action }}
        {{ if eq (printf "%T" $index) "int" }}
          {{ if not
            (or
              (and (ge $index 0) (le $index (sub $length 1)))
              (and (lt $index 0) (le (mul $index -1) $length))
            )
          }}
            {{ errorf $msg6 }}
            {{ $error = true }}
          {{ end }}
        {{ else }}
          {{ errorf $msg5 }}
          {{ $error = true }}
        {{ end }}
      {{ else }}
        {{ errorf $msg4 }}
        {{ $error = true }}
      {{ end }}
    {{ else }}
      {{ errorf $msg3 }}
      {{ $error = true }}
    {{ end }}
  {{ else }}
    {{ errorf $msg2 }}
    {{ $error = true }}
  {{ end }}
{{ else }}
  {{ errorf $msg1 }}
  {{ $error = true }}
{{ end }}

{{ if not $error }}

  {{ if eq $action "delete" }}
    {{if ge $index 0 }}
      {{ $firstPart = $slice | first $index }}
      {{ $lastPart = $slice | last (sub (sub $length $index) 1) }}
    {{ else }}
      {{ $firstPart = $slice | first (add $length $index) }}
      {{ $lastPart = $slice | last (sub (mul $index -1) 1) }}
    {{ end }}
    {{ range $firstPart }}
      {{ $newSlice = $newSlice | append . }}
    {{ end }}
    {{ range $lastPart }}
      {{ $newSlice = $newSlice | append . }}
    {{ end }}
  {{ end }}

  {{ if eq $action "insert" }}
    {{ if ge $index 0 }}
      {{ $firstPart = $slice | first $index }}
      {{ $lastPart = $slice | last (sub $length $index) }}
    {{ else }}
      {{ $firstPart = $slice | first (add (add $length $index) 1) }}
      {{ $lastPart = $slice | last (sub (mul $index -1) 1) }}
    {{ end }}
    {{ range $firstPart }}
      {{ $newSlice = $newSlice | append . }}
    {{ end }}
    {{ $newSlice = $newSlice | append $item }}
    {{ range $lastPart }}
      {{ $newSlice = $newSlice | append . }}
    {{ end }}
  {{ end }}

  {{ if eq $action "replace" }}
    {{ if ge $index 0 }}
      {{ $firstPart = $slice | first $index }}
      {{ $lastPart = $slice | last (sub (sub $length $index) 1) }}
    {{ else }}
      {{ $firstPart = $slice | first (add $length $index) }}
      {{ $lastPart = $slice | last (sub (mul $index -1) 1) }}
    {{ end }}
    {{ range $firstPart }}
      {{ $newSlice = $newSlice | append . }}
    {{ end }}
    {{ $newSlice = $newSlice | append $item }}
    {{ range $lastPart }}
      {{ $newSlice = $newSlice | append . }}
    {{ end }}
  {{ end }}

{{ end }}

{{ return $newSlice}}

Try it
git clone --single-branch -b hugo-forum-topic-34797 https://github.com/jmooring/hugo-testing hugo-forum-topic-34797
cd hugo-forum-topic-34797
hugo server

Then visit http://localhost:1313/tests/test-1/

1 Like

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