[solved] Randomizing an array

I am unsure how to randomize a collection. In this specific case I want to randomize a tag cloud.

{{ range $name, $taxonomy := $.Site.Taxonomies.tags }}

The above snippet ranges through my tags sorted alphabetically. Now I would think adding shuffle would randomize it. But it doesn’t :slight_smile: Is there any documented way to “shuffle” the tags “array”?

{{ range $name, $taxonomy := ($.Site.Taxonomies.tags).shuffle }}

^ not working :wink:

Order by random would also be a nice functionality probably…

I think the correct way would be to pipe the tags to the shuffle function. However, this raises an error:

<shuffle>: error calling shuffle: can't iterate over hugolib.Taxonomy

That’s because shuffle manually checks for variable type before iterating over it, and taxonomies are not in the whitelist. I think part of the problem has to do with shuffle expecting a list/array and not a dictionary. So unfortunately even this doesn’t work:

{{ $.Scratch.Set "tags" (dict) }}
{{ range $name, $taxonomy := ($.Site.Taxonomies.tags) }}
    {{ $.Scratch.SetInMap "tags" $name $taxonomy }}
{{ end }}
{{ range $name, $taxonomy := $.Scratch.Get "tags" | shuffle }}
    {{ $name }}
{{ end }}

What if you create a “tags” slice instead of a dict, shuffle that, range through that, use the elements as index of the actual tags map, and reconstruct a new shuffled map in Scratch?

1 Like

That works perfectly indeed, thanks! I actually made it slightly shorter (2 ranges instead of 3):

{{ $.Scratch.Set "tags" (slice) }}
{{ range $name, $taxonomy := ($.Site.Taxonomies.tags) }}
    {{ $.Scratch.Add "tags" $name }}
{{ end }}
{{ range $name := $.Scratch.Get "tags" | shuffle }}
    {{ $taxonomy := index $.Site.Taxonomies.tags $name }}
    {{ $name }} - {{ $taxonomy }}<br>
{{ end }}
2 Likes

I am not sure what’s happening, but it’s working now :slight_smile:

{{ if not (eq (len $.Site.Taxonomies.tags) 0) }}
    {{ $fontUnit := "rem" }}
    {{ $largestFontSize := 2.0 }}
    {{ $largestFontSize := 2.5 }}
    {{ $smallestFontSize := 1.0 }}
    {{ $fontSpread := sub $largestFontSize $smallestFontSize }}
    {{ $max := add (len (index $.Site.Taxonomies.tags.ByCount 0).Pages) 1 }}
    {{ $min := len (index $.Site.Taxonomies.tags.ByCount.Reverse 0).Pages }}
    {{ $spread := sub $max $min }}
    {{ $fontStep := div $fontSpread $spread }}
	        
	<h3>Themen auf Samui? Samui!</h3>

	<div class="text-center">

	{{ $.Scratch.Set "tags" (slice) }}
	{{ range $name, $taxonomy := ($.Site.Taxonomies.tags) }}
	    {{ $.Scratch.Add "tags" $name }}
	{{ end }}
	{{ range $name := $.Scratch.Get "tags" | shuffle }}
		{{ $taxonomy := index $.Site.Taxonomies.tags $name }}

	    {{ $currentTagCount := len $taxonomy.Pages }}
	    {{ $currentFontSize := (add $smallestFontSize (mul (sub $currentTagCount $min) $fontStep) ) }}
	    {{ $count := len $taxonomy.Pages }}
	    {{ $weigth := div (sub (math.Log $count) (math.Log $min)) (sub (math.Log $max) (math.Log $min)) }}
	    {{ $currentFontSize := (add $smallestFontSize (mul (sub $largestFontSize $smallestFontSize) $weigth) ) }}
	    <!--Current font size: {{$currentFontSize}}-->
	    <a href="{{ "/tags/" | relLangURL }}{{ $name | urlize }}" rel="tag" style="font-size:{{$currentFontSize}}{{$fontUnit}}">{{ $name }}</a>
	{{ end }}

	</div>

{{ end }}

I will google all the things that are going on :slight_smile:

2 Likes

Well shuffle does not work with dictionaries (name => key entries) but merely with lists/slices (name entries). So because your taxonomy is a dictionary of names pointing to lists of pages, the shuffle function is unable to deal with this.

So we need to create an intermediary list in scratch, containing only the names of tags, and not the pages associated. This, shuffle can deal with and so from this shuffled list of names, we’re able to fetch the associated pages in the taxonomy.

Is that more clear now? Don’t hesitate to ask more questions :stuck_out_tongue:

Thats more clear, thank you :slight_smile: dictionaries is a new concept to me (coming from php, where there is no distinction between two- and multidimensional arrays). I am reading a lot of Golang documentation these days, but that’s like a second language to me sometimes, hehe.

1 Like

I don’t even think that’s the word gophers use. I think they refer to to one-dimensional arrays as slices, and two-dimensional arrays as maps. (Of course you can simply wrap a map in a map to get more dimensions)

I think the terms I employed come more from the Python world, but I feel like they are easy to understand. A list is an ordered list of values, while a dictionary is an ordered/unordered (depends on the implementation) of names pointing to a value.

In golang apparently, maps (dictionaries) are not ordered. So contrary to what I was suggesting before, I don’t think it’s an easy task for shuffle to support dicts as well. Because it may as well return an ordered dict (i.e. randomized, in our case) but range will not follow this order while iterating over it.

So maybe now that we have a nice template-level hack thanks to @kaushalmodi, this can be considered solved? :slight_smile:

1 Like

Just a style/clarity thing I learned from Lisp: As the $taxonomy is not used in that loop, I would simply do {{ range $name, $_ := ($.Site.Taxonomies.tags) }}.

That way, the user can read that $_ as “whatever”, and quickly understand that that’s an unused variable (of course if this convention becomes wide-spread :slight_smile:).

I brought this up because later in the code, you create a new $taxonomy var which has nothing to do with that unused $taxonomy.


One of my $_ uses.

1 Like