Filter to test whether two sets/lists differ?

Hi everyone, I’d like to compare two lists (described by filters) in order to know whether they are equal or if they differ (by at least one item). This may look like an easy problem to solve in one filter, but I have been stuck on this one for too many hours, because the sets may also be empty!
If you know a general recipe, please tell me :slight_smile:
If you want to test your solution, here is some wikitext to work on on tiddlywiki.com.

\define set-0_filter()
\define set-1_filter() Open Recent Tools More +[addprefix[$:/core/ui/SideBar/]]
\define set-2_filter() [list[$:/tags/SideBar]] 

* set #0={{{ [subfilter<set-0_filter>] ||$:/core/ui/ListItemTemplate }}}
* set #1={{{ [subfilter<set-1_filter>] ||$:/core/ui/ListItemTemplate }}}
* set #2={{{ [subfilter<set-2_filter>] ||$:/core/ui/ListItemTemplate }}}

This naïve solution only works when set 1 is non empty:
''<$list filter="[subfilter<set-1_filter>sort[]join[&]] -[subfilter<set-2_filter>sort[]join[&]]"
         emptyMessage="Sets are the same">
Sets differ
</$list>''

Thanks in advance!

[subfilter<set-0_filter>sort[]join[&]else[]] -[subfilter<set-2_filter>sort[]join[&]else[]]

If there’s a chance that a list may contain only an single value, which is an empty string, then you could go with “[else[$:/myPlugin/emptyList]]” or something else you can be sure will never appear in the lists.

Hi @Flibbles this is brilliant! Thank you so much!
–Xavier.

Also look at the Kin filter since this allows you to get a set of tiddlers for more complex filters including hierarchical lists similar to the TOC macro. It is then possible to subtract one list from another ,add one list to another eg find ever tiddler in a tree but exclude those below the current tiddler and more. Now also with Intersections

Also you can test if a list is non-empty or !is[blank] before you list comparison as well.

I am looking forward to ensuring tiddlywiki has easy methods for set manipulation to enhance its existing list manipulation. It is all just a matter of using the tools already available.

Hi Anthony,
The kin filter is indeed powerful although it’s not immediately obvious to see how it could be used in this case. Furthermore, as I’m working on a plugin, I try to minimise the number of dependencies.

I also agree that we can manipulate sets with the current (5.2.0) filter operators, but empty sets are special beasts. Thanks to @Flibbles, I realised that else[] could be used to tame them.

Still, it seems awkward to rely on comparing two strings built from the sets elements in order to tell whether two sets are the same. There is certainly room for specific comparison operators.

The Kin filter was a way to simplify a list or set build from a hierarchy, But you can get such a list with your own set of recursive macros.

Then it should be simple to compare two lists. One way maybe to use count to establish if the lists have the same number of elements, only then then list one excluding the items from the other list "[Enlist<list gen 1>] -[subfilter<list gen 2>]] if nothing is returned then they are the same. The nul case with the $list is emptyMessage and the $set is emptyValue.

I find no problem’s with empty sets and you seemed close in your original post.

Can you create a simplified example that runs on tiddlywiki.com?, I am confident there are a number of ways to Filter to test whether two sets/lists differ.

Your example does illustrate the empty set issue: if <<list gen 1>> is empty, then the filter returns nothing, whatever the value of <<list gen 2>> is.

Here is the modified code that uses a default value in case of empty sets. You can paste it on a new tiddler on tiddlywiki.com and change the values in order to see what happens.

\define set-0_filter()
\define set-1_filter() Open Recent Tools More +[addprefix[$:/core/ui/SideBar/]] 
\define set-2_filter() [list[$:/tags/SideBar]] 

* set #0={{{ [subfilter<set-0_filter>] ||$:/core/ui/ListItemTemplate }}}
* set #1={{{ [subfilter<set-1_filter>] ||$:/core/ui/ListItemTemplate }}}
* set #2={{{ [subfilter<set-2_filter>] ||$:/core/ui/ListItemTemplate }}}

This new solution works even when set 1 is empty:
''<$list filter="[subfilter<set-1_filter>sort[]join[&]else[$:/plugins/xc/default value]] -[subfilter<set-2_filter>sort[]join[&]else[$:/plugins/xc/default value]]"
         emptyMessage="Sets are the same">
Sets differ
</$list>''

As a codicil, I just wanted to acknowledge that thanks to the default value technique on empty sets, there is no point anymore (has it been ever?) to concatenate items before comparison. So the following code…

\define default-if-empty() $:/plugins/xc/default value for empty sets

\define set-1_filter() Open Recent Tools More +[addprefix[$:/core/ui/SideBar/]] 
\define set-2_filter() [list[$:/tags/SideBar]]

<$list filter="[subfilter<set-1_filter>else<default-if-empty>] -[subfilter<set-2_filter>else<default-if-empty>] +[limit[1]]"
         emptyMessage="Sets are the same">
Sets differ
</$list>

… is definitely enough for the identity test I was after.

1 Like

Thanks for reporting back, it helps those that follow.