Several Filter Runs in One Go

A code processes names has several conditions, one solution is to use several $list widgets, the other is to use several filter runs, what solution do you recommend?

Example: Parse names and return family name? Names are stored as First Last and Last, First

<$let names="[[Jeremy Ruston]] [[Imtiaz, Saq]]">

<$list filter=" [enlist<names>] :filter[search:title[,]] :map[split[ ]first[]trim[,]]
                [enlist<names>] :filter[!search:title[,]] :map[split[ ]last[]]        "
>

</$list>


</$let>

produces

Imtiaz
Ruston

What is the simpler solution using several filter runs in one go (in one $list)?

It depends on what you need to do with the results.

If all you want is to output the lists, then either multiple $list widgets or multiple filter runs in a single $list widget will suffice. For this use-case, I’d base my decision on how “readable” the code is.

However… suppose you want to sort the results by last name. For this purpose, a single $list widget makes sense, like this:

<$list filter="
   [enlist<names>] :filter[search:title[,]] :map[split[ ]first[]trim[,]]
   [enlist<names>] :filter[!search:title[,]] :map[split[ ]last[]]
   +[sort[]]
"/>

-e

3 Likes

Good question @Mohammad

Following on @EricShulman’s answer, if you can easily write a single filter that is not too hard to understand when you return in 2 years, then do it.

I must be honest the above filter, although it makes sense because you told me, It’s not clear how the use of [enlist<names>] twice guarantees the result (it does it needs a level of expertise with filters, to identify there are two complementary filter runs).

For me the key and value reason for nested list widgets includes;

  • You want to make use of an intermediate value by making it the
    variable=intermediate-value
    • This is commonly because you want the original tiddler title
  • To simplify the filter(s)

Finally I think people often feel nested lists are somehow inferior to complex filters, but this is not true.

Now with the map and reduce operators, filters can get a lot more complex. However I think this missing the fact that,

Just because you put the logic in one filter it does not (necessarily) reduce the amount of work to be done, and certainly can make the filter(s) harder to read.

  • and may even miss opportunities to make use of internal indexing see Performance.

Nesting $list widgets

When you nest $list widgets not only do you get intermediate results, you also have the opportunity to insert different responses at different places in the process in both outer and inner lists. This is even more so now, with the counter variable. Here is a basic example within which more complex processing could be done for <<each-item>>;

<$set name=total filter="$filter$ +[count[]]">
<$list filter="" emptyMessage="" counter=item variable=each-item>
   <$list filter="[<item>match[1]]" variable=~>On first</$list>
   <<each-item>><!-- replace with an innerlist -->
   <$list filter="[<item>match<total>]" variable=~>On last</$list>
</$list>
</$set>

I would also add that rather than “cramp one filter into another” or “use nested list widgets” another form of nesting, which also has benefits comes from the increasingly useful “filtered transclusions”.

Filtered transclusions as inner lists

If we return to @Mohammad initial example is this perhaps better?

<$let names="[[Jeremy Ruston]] [[Imtiaz, Saq]]">
<$list filter=" [enlist<names>]" variable=person>
   Surname: 
   {{{ [<person>] :filter[search:title[,]] :map[split[ ]first[]trim[,]] }}}
   {{{ [<person>] :filter[!search:title[,]] :map[split[ ]last[]] }}}
   <br>
</$list>
</$let>

notice how

  • all key values have named variables eg person
  • its easy to insert additional formatting or call other macros
  • You can treat first, other and last items differently

The only disadvantage with “filtered transclusions” is we often have to use the text widget.
<$text text={{{ [<person>] :filter[!search:title[,]] :map[split[ ]last[]] }}}/>

  • I wish we had a simple way to force a filtered transclusion to return text.
  • Perhaps this will come one day.