Keeping an intermediate result in a filter expression - and reusing it?

Situation
A whole filter expression consists of two filter runs.
The first filter run is expensive.
The second filter run is a duplicate of the first, but adds a suffix to each title.

Craving
Still within a single filter expression, get the same output, but avoid duplicating the expensive first run?

I.e do the expensive first run and keep the output list of titles but also use the already calculated list of titles and add the suffix, e.g: AAA BBB AAAsfx BBBsfx The order in the final output is not important.

Ramification
Global harmony

Realization
If the above is possible then maybe it would also solve the (for me) recurring problem:

[tag[friend]get[phonenumber]] …now who is that number to again?

{{{ [tag[friend]] :map[<currentTiddler>addsuffix[ - ]addsuffix{!!phone}]  }}}

It’s not technically a single filter, but I’ve been doing this sort of thing with functions:

\function and.with.suffix(suffix) [all[]] [all[]addsuffix<suffix>]

{{{ [tag[HelloThere]and.with.suffix[sfx]] }}}

Relatedly (I think?) I’ve occasionally wished I could define a named variable at the end of a filter run and then reuse it later in the filter… but I can’t remember the specific circumstances that prompted this wish, so I’m not sure if I’d still long for it, or if I’d just reach for a function instead.

I also often use $let or $set to pre-compute costly filters and save the results as single-string variables that I can just enlist each time I need them. It’s not quite as neat as what you’re envisioning, but at least it avoids running the same filter more than once.

1 Like

Thanks. Yeah, doable but not optimal. I wish there was a less hackey solution.

I’m more and more getting to like functions. Indeed not a single filter but IMO also better than enclosing let/setwidgets or such that directly makes alread visually complex code more complex. Thanks.

1 Like

As “no doubt you have heard” me provide constructive criticism to the tendency to force things into single filters, when it is often, not at all necessary?

  • Nesting is usually just as efficient and fast and sometimes much faster if you do not need to re-evaluate because the filter only handles one title at a time.
  • Nesting allows intermediate variables and code insertion point that a compound filter does not.

This is a good example of this where a single list widget is fine

<$list filter="[tag[friend]]">

{{{ [all[current]addsuffix[ - ]addsuffix{!!phone}] }}}
etc...

</$list>
  • of course you can use the lists variable widget to change another variable not current tiddler
  • The same method can nest multiple list widgets, use functions etc… and if you name the list widgets variable that is available, go as many levels deep as you want and still have access to the variables “above”.
  • The costly filters use can be minimised without complex filters.
  • Tests can be put in place for the first item in the list, the last item in the list, not first/last item or use multilevel counters.

What part confuses you @CodaCoder ?

Right, it is often not necessary, but sometimes it is! And sometimes it is merely desirable given the context. It can even be a matter of aesthetics. All valid reasons :slight_smile:

The “friend phone” matter was merely an illustration of how it sometimes is desirable if information could be carried forward in a filter.

Mmm, that’s somewhat close to what l was just working on. Something like this ?

\function get.fields() [all[]] :map[compute.fields<currentTiddler>]
\function compute.fields(currentTid)
  [<currentTid>format:titlelist[]]
  [<currentTid>get[phone]addprefix[-]addprefix<currentTid>format:titlelist[]]
  [<currentTid>get[group]addprefix[-]addprefix<currentTid>format:titlelist[]]
  +[join[ ]]
\end compute.fields

{{{[tag[friend]get.fields[]]}}}

I find there’s lots of flexibility within the compute.fields function. I can use the variable <currentTid> freely in multiple filter lists, then join all the results together with an appropriate separator (linefeed for lines, space for titles, slash for path, etc) to return one single value for the function.

Right! It is neat to abstract things away as custom filter ops. Thanks for sharing!

The \end <name> is only needed if the function or procedure is nested inside a procedure. So in your case \end would be enough.

I think it improves readability to include the name in the \end pragma, and wouldn’t consider it a mistake.

I did not say it is a mistake. If I need to change the name, it makes it harder for me, because there are 2 places to change it. Especially, if the name change is only temporary. The difference is subtle, but it does slow me down quite a bit.