Is there a way to subtract a collection from another one? I can’t seem to find any function that does that.
Here’s what I’m trying to do on the same page:
Display 4 latest posts – easy.
Display 4 random posts but avoid duplicates with the posts already displayed in (1).
Essentially, I’m missing the operation SUBTRACT
from the listing below.
{{ $latest := first 4 (where .Pages "Type" "posts") }}
{{ $randomCandidates := SUBTRACT (where .Pages "Type" "posts") $latest }}
{{ $random := first 4 (shuffle $randomCandidates) }}
I did something similar using the following code:
{{ range first 6 (after 3 (.Data.Pages.ByDate.Reverse)) }}
The first 3 articles are already displayed separately…
Cool workaround. It’ll work for this case, but not for some other cases that I didn’t post here for clarity.
intersect
returns common elements, while I would need something more like xor
.
bep
November 3, 2018, 1:16pm
6
I wrote the above on mobile, hence the “brevity”.
{{ $latest := first 4 (where .Pages "Type" "posts") }}
{{ $randomCandidates := (where .Pages "Type" "posts") }}
{{ $randomCandidates = $randomCandidates | intersect (where $randomCandidates "not in" $latest) }}
{{ $random := first 4 (shuffle $randomCandidates) }}
The above is totally intested, of course …
1 Like
bep
November 3, 2018, 1:35pm
7
Of course, looking at the above, the intersect is superflous:
{{ $latest := where .Pages "Type" "posts" | first 4 }}
{{ $randomCandidates := (where .Pages "Type" "posts") }}
{{ $randomCandidates = where $randomCandidates "not in" $latest }}
{{ $random := $randomCandidates | shuffle | first 4 }}
1 Like
Ah, now I see. Didn’t know that where ... "not in"
accepted whole objects. Thanks!
Not quite there yet. This part:
{{ $randomCandidates = where $randomCandidates "not in" $latest }}
causes an error:
executing “main” at <where $randomCandida…>: error calling where: not in isn’t a field of struct type *hugolib.
I guess that’s because where
expects a key
as the second parameter? What should be the key here?
bep
November 3, 2018, 3:49pm
10
I was wrong, the above does not work. I will get back to you if I come up with something that actually works.
Hugo lacks difference and symmetric difference functions to go along with union
and intersect
. We should consider adding those.
As was already noted, a naive solution to your example:
{{ $set := where .Pages "Type" "posts" }}
{{ $latest := first 4 $set }}
{{ $random := first 4 (shuffle (after 4 $set)) }}
The only way to accomplish the subtraction/difference logic today is to key off of a unique Page property:
{{ $set := where .Pages "Type" "posts" }}
{{ $latest := first 4 $set }}
{{ $exclude := slice }}
{{ range $latest }}{{ $exclude = append .Filename $exclude }}{{ end }}
{{ $random := first 4 (shuffle (where $set "Filename" "not in" $exclude)) }}
4 Likes
Thanks for that @moorereason , it works. If you can add explicit difference functions that’d be grand too
bep
November 3, 2018, 9:22pm
13
Yes, that would be useful, if we could find good names.
1 Like
I suggest “complement” for the set difference, just as Wolfram do (and we could have it for multiple sets), e.g. complement setA setB setC ...
would output all elements of setA that are not in setB, nor in set C, etc.
(No good name idea for symmetric difference).
bep
November 6, 2018, 7:32am
16
I have implemented the complement funcion – but when I was looking for a good example for the docs, I see that the above isn’t a particular good one, as it could be rewritten as:
{{ $all := where .Pages "Type" "posts" }}
{{ $first4 := $all | first 4 }}
{{ $randomCandidates := $all | after 4 }}
{{ $random := $randomCandidates | shuffle | first 4 }}
ju52
November 6, 2018, 3:55pm
17
bep
November 6, 2018, 4:54pm
18
I have boldly added:
I’m open to change the names above if someone can come with a convincing argument. I guess “complement” reads nicely, symdiff not so much.
1 Like
Just tried out the newly released complement
– works superbly. Thank you!
1 Like
bep
November 7, 2018, 5:02pm
20
Thanks for the compliment on the complement.
2 Likes