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