Help with compound filters

Folks,

I have a filter typically [tag[tagname]] and another filter, sometimes found in a field on another tiddler, it may have any filter such as -[[not this tiddler]] -[prefix[$:/tags/a]] [[add this tiddler]]

Reading it

  • Give me all titles with the tagname
  • If one has the title “not this tiddler” remove it from the list
  • Also remove any with the prefix $:/tags/a
  • And include in the lists a title not in the list so far “add this tiddler”

So The result should be effectivly;

[tag[tagname]] -[[not this tiddler]] -[prefix[$:/tags/a]] [[add this tiddler]]
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The second filter found in the field on another tiddler is now stored in a variable.

Question

How do I combine these two filters to get the outcome one would expect?

I am not sure why I have a “coders block” on this.

subfilter{!!field} or subfilter<var> gets you part of the way there… but it can’t remove results from a previous filter run. Here’s a quick example to demonstrate.

In both cases below, I stored my “remote” filter in the filter field of my testing tiddler:

[tag[Filter Operators]first[10]] -[tag[Mathematics Operators]] -[[A Gentle Guide to TiddlyWiki]] -[prefix[D]]

The upper list shows the results for [tag[HelloThere]] [subfilter{!!filter}] (which would produce the same results in a $list widget, or a filtered transclusion, or as a function-as-filter-operator, etc.) You can see that while I can remove -[tag[Mathematics Operators]] from the results introduced by [tag[Filter Operators]first[10]], I can’t remove any of the results of [tag[HelloThere]] as it’s not part of the subfilter.

On the other hand, if you’re using a $list widget, you can use filters to construct the filter string itself as a substituted attribute value, then run it to get the results. Here’s the code I used above:

<$list filter=`[tag[HelloThere]] ${ [{!!filter}] }$`>

Note that [tag[HelloThere]] is inside the backticks but outside the ${ }$ that marks a filter to be evaluated: it doesn’t need to be evaluated in the first substitution step.

1 Like

Try this

[tag[tagname]] +[subfilter<variable>]

-e

Thanks Folks, Exploring now.

I should have mentioned, for now it is inside a %if.

I tried this <%if [subfilter<display-filter>] +[subfilter<disregard-filter>] %> with no luck, I will try a $list widget as per @etardiff

I am confusing myself. Somehow, Thanks for you help back soon.

I think you probably know this already, but just in case it helps…

There’s a subtle but crucial difference between [subfilter<var>] (as in my first post) and +[subfilter<var>] (as in Eric’s suggestion), and that’s the input values they take.

  • [subfilter<var>] is a stand-alone filter run, so (like all runs without an explicit filter run prefix) it starts from an implicit all[tiddlers].

    • e.g., my first example (which didn’t produce your desired results) could be rewritten as [tag[HelloThere]] [all[tiddlers]subfilter{!!filter}]
    • This is also the reason why subfilter, used this way, can’t remove results from a previous run: it’s completely independent and starts “from scratch”. Any -[[My Tiddler]] present in the subfilter will remove “My Tiddler” from the results of the second filter run (starting with all[tiddlers]), but not the first.
  • +[subfilter<var>] modifies each result of the preceding run.

    • [tag[HelloThere]] +[subfilter{!!filter}] could be rewritten [tag[HelloThere]subfilter{!!filter}] — IMO, this makes it clearer which inputs are being used.
    • As you can see below (top filter/field pair in the preview window), this means that, depending on the “starting” filter and the contents of the subfilter, you may not get the expected results. That’s because, in a subfilter used this way, [tag[Filter Operators]...] isn’t adding a new set of tiddlers to the previous input of [tag[HelloThere]]. Instead, it’s filtering the results of [tag[HelloThere]] down to only those that also meet the tag[Filter Operators] conditions — in this case, none of them. So a selection constructor like [[HelloThere]] will still add its results, but most of the runs in the subfilter may not “work.”
  • We can mitigate this issue with +[subfilter...] by modifying the contents of the subfilter itself. In the second example below, you can see some changes I made:

    • Start with the selection constructor [all[]] to pass on all the results of the previous filter run.
    • For any runs intended to introduce new sets of tiddlers “from scratch” (like [tag[Filter Operators]]) or modify new sets introduced in this way (like [tag[Mathematics Operators]]), you’ll need to start the run with all[tiddlers]. Below, you can see…
      • [all[tiddlers]tag[Filter Operators]first[10]] contributes its output to the final results.
      • -[tag[Mathematics Operators]] doesn’t start with all[tiddlers], so it doesn’t remove results added by [all[tiddlers]tag[Filter Operators]]. (It would remove any [tag[HelloThere]] tiddlers that also had the “Filter Operators” tag, though, if there were any.)
      • In the same vein, -[[A Gentle Guide to Tiddlywiki]] and -[prefix[D]] remove results contributed by the original [tag[HelloThere]] run.

So writing a subfilter that will “work” when used this way is obviously quite complex and potentially error-prone.

But! It’s not only unintuitive, it’s also inefficient, because each result of the initial filter run must be passed through every step of the subfilter, where any selection constructors will contribute unneeded duplicates!

:grinning:

… anyway, I’d try to use $list with a substituted attribute value for filter if at all possible. :sweat_smile:

1 Like

Thanks Emily,

I have this 90% clear in my head. I do agree with your approach of using the backticks for “substituted attribute values” to “construct the filter to be used”, then giving that to the filter attribute.

  • Thanks, I am confident the issues I face and solution resides somewhere in what you documented.

In my current piece of work I am using this;

<$list filter=`[[$(viewCard)$]subfilter<display-filter>]` variable=~>

Which tests if the specific viewcard is to be displayed. That is the filters are simplified through nesting $lists (thus filters). The cards were iterated in an outer list. Its only when I try and foce this all into the one filter that it gets tricky. The reason we may do this is to simplify the number of changes we may request in the core tag iterations. For disregards etc…

  • Perrhaps I should simplify this and use a nested list

My idea is not no so much have a disregard-filter but a “single” filter capable of ruling things in and out , just a filter. But importanly a filter that is applied to the output of a prior filter (via an external refererence).

I suppose if we consider your example we could replace the whole filter and include [tag[HelloThere]] in the new filter.

  • I would have thought existing filter run prefixes could help us here.

You may have noticed I have being putting in 100s of hours on TiddlyWiki of late. I have solved many problems, some of which are said to be unsolvable, so TiddlyWiki is all very current and focused for me.

Thanks for your assistance, very much.

I don’t know what sort of content you have in [$(viewCard)$] (and note that there’s no real reason to use the backtick syntax if you don’t have any other substitutions happening in the filter — [<viewCard>...] should work just as well) or <display-filter>, so this is a hunch more than anything, but be wary of the difference between subfilter and filter.

  • subfilter (potentially) modifies its input via a filter, and its output(s) are the results of that filter.
  • filter runs each input through a filter and returns an input value, unchanged, if the filter produces any result.

If what you want to (conditionally) display is <<viewCard>> itself, you may want to use filter rather than subfilter.

Good luck!

1 Like

Yes, Sorry. the example I have only works because there are nested lists. I would want to apply an additional filter after the example I gave.

I have learned in experiments with delisting tags, we have two possible things;

  • first, remove a tag from the those itterated according to a condition on that tag.
  • Second, for a given tiddler, while itterating the tag remove those excluded by the given tiddler itself.

I mention this because it illustrates the need to apply more than one filter after the initial one. Idealy also to include or exclude.