Siblings filter

Hi,
I am trying to create a filter which get all the siblings of particular tiddler, but I have quite a hard time finding how to do that.

My tiddlers are persons with a “parents” field.
I manage to get all the children like that :

<$list filter="[contains:parents<currentTiddler>]" >
<<currentTiddler>>
</$list>

And here is one of the numeros things I tried to get the siblings :

<$list 
filter="[<currentTiddler>get[parents]split[ ]]:map[all[tiddlers]contains:parents<currentTiddler>]" >
<<currentTiddler>>
</$list>

The problem is that the :map operator only transform one to one.

I tried a lot of other things, but here I am lost.

Thanks for your help

Hi, I’m not sure if this will help you out, but I did create a “parent” based tocP plugin. …

But, it is built to have only 1 title in the parent field. So from your post I think you want to have more than 1 title in there. … right?

1 Like

Try using the :reduce filter run prefix or nested lists if that works for your use case.

Untested code:

[<currentTiddler>get[parents]enlist-input[]]
:reduce[all[tiddlers]contains:parents<currentTiddler>format:titlelist[]join[ ]addsuffix[ ]addsuffix<accumulator>] :and[enlist-input[]]
4 Likes

Hi, Thank you for your plugin.

Yes you are right, my tiddlers have multiples parents.

I think what I am really searching for, is how to use the input tiddlers of a step or a run, as a parameter for other runs.
“:map” was almost it, but not exactly because : “Filter runs used with the :map prefix should return the same number of items that they are passed.”

Wow it seems to work, thank you a lot.

I already tried reduce, but I think I misunderstood how it works exactly, I will try to understand what you did.

@pmario TocP allows an alternative field, so if it were important one could have a matrilineal and patrilineal tree, with the children the sum of both. But with Genealogy things can get complex eg steps parents, half siblings etc…

Here is another way that doesn’t manually build a title list:

\define filtrate() [list[!!parents]] :intersection[enlist<parentlist>]

<$set name="parentlist" filter="[[Name of tiddler to find siblings for]get[parents]enlist-input[]]" >
  <$set name="output" filter="[all[tiddlers]has[parents]] :filter[subfilter<filtrate>]">
    <$text text=<<output>> />
  </$set>
</$set>

There is absolutely nothing wrong with @saqimtiaz’ solution. For some unknown reason I’m just not partial to manually building title lists from a list of titles. Call me crazy.

How it works:
The parents of the child are put into a variable parentlist to avoid multiple lookups later. Then, all tiddlers with a parent field are filtered (the :filter) by checking if their parent field has some overlap (the :intersection) with the parentlist.

Have a nice day
Yaisog

PS: I really wish there was a :foreach filter run prefix in TW. Probably wouldn’t be too hard to implement, since it’s basically what :filter does without discarding the results…

PPS: I updated the code to use the old-school list operator instead of get[parents]enlist-input[] in the subfilter.

1 Like

I’m sure you’ll have examined it already, but could the “map” filter run prefix help?

https://tiddlywiki.com/#Map%20Filter%20Run%20Prefix

I did have look at that, indeed. However, if the result for each input title would / could be a list of titles, it would again be necessary to join these into a title list and then enlist them like @saqimtiaz did above and I’m no great fan of. I do like map a little better than reduce in this case, as it is slightly more straightforward and/or semantic.

Have a nice day
Yaisog

@Yaisog if you have not already consider @bimlas Kin filter TW5 Kin filter plugin — recursively looking for kinship between tiddler titles which hides all the recursive tree walking inside the filter. You can also use multiple kin filters and add and subtract the members to get other sets of tiddlers, like find the current tiddlers siblings or cousins etc…

I recommend the kin filter for genealogy.

The kin filter is actually an excellent choice here. I used to have it in my wikis. But when you get to a point with a LOT of tiddlers and a tag tree that is multiple levels deep, the kin filter really slows things down compared to using the various tag*-filters, as I don’t think it makes use of the caching mechanism that makes these filters blazingly fast.
For genealogy it’s probably perfect and well documented. Thanks for bringing it up in the context of the OP.

My contribution to this thread is purely for the enjoyment of finding different and hopefully elegant solutions to problems, which is always possible with TW.

Have a nice day
Yaisog

PS: The broader topic interests me, because I’m still looking for an elegant replacement for the kin filter to find all tiddlers in the hierarchy of a tag (tagged with the tag or with the children of this tag and so forth, no matter how many levels deep). The kin filter did that, but very slowly. See also my post a https://groups.google.com/g/tiddlywiki/c/ws05-YAtJ7k/m/uOLPwMABDgAJ.

Of course you havelooked at built in toc macros?

Also if you search here and in google groups I have posted on recursive macros which are exactly what you need.

Thanks for the tip, but actually I’m looking for a filter, not a macro. Even now that macros can be called from a filter, it would require manually assembling a tiddler list from a list of tiddlers, which from my personal perspective is not an elegant solution (unless such filter functionality ever makes it into the core).

Have a nice day
Yaisog

Not necessarily. A filter can generate a list of tiddler or be a list of manually entered tiddlers, or both.

Be carful not to create a false dichotomy between filter and macros, The same is commonly also done between filters and nested filters.

  • All a macro is is capturing your algorithm into something you can invoke in more than one place, and allows you to make it reusable including by providing parameters or variables to that macro.
  • All a nested filters (lists) are, is wrapping one filter in another and can also provide additional values/variables to the inner filter.
    • Recursive macros nest one filter in another, in my example below it is the same filter.
  • A recursive macro is a special case where a macro calls itself, as many times as the data demands, arguably this is the only way to travers a hierarchy of any kind, as you wish to do.
    • To do a recursive function we need a macro so we can call ourself. Thus a macro is essential.
    • In this example first-level kicks off the process and each-other-level calls itself as it runs down the hierarchy. When it reaches every leaf (bottom nodes in a hierarchy) , it falls back to the next sibling at the level above.

Here is a really simple example you can edit; try it on tiddlywiki.com

Example-recursive-toc.json (579 Bytes)

\define each-other-level(filter)
<li><$link to=<<currentTiddler>> ><$text text=<<currentTiddler>>/></$link></li>
<ul>
<$list filter="$filter$">
   <<each-other-level $filter$>>
</$list>
</ul>
\end
\define first-level(filter)
<ul>
<$list filter="$filter$">
   <<each-other-level $filter$>>
</$list>
</ul>
\end

Start in TableOfContents<br>
<$tiddler tiddler="TableOfContents">

<<first-level "[is[current]tagging[]]">>

</$tiddler>
  • I am not testing to avoid loops here but often we do not naturally create loops.
1 Like

@TW_Tones: Thanks for the example. I believe this is how the TOC macros work.

What I need, however, is not a printed out list-of-lists of the hierarchy, which can be assembled level by level as you show, but all of the tiddlers in the hierarchy in a single list as returned by a single filter call, i.e. something like

<$set name="allTiddlersBelow" filter="[[TableOfContents]taggingtree[]]">

that will put all the tiddlers that would appear somewhere in the lists of your example into one single list of tiddlers / variable that I can work with. taggingtree[] is a (yet) fictional operator which would do that.
Have a nice day
Yaisog

Well yes that is what the kin filter does.

There is away to craft the above macro to return a simple list of all found tiddlers as well.

I will place it here shortly.

The trick are

  • to rewrite the macro to only list titles (in title list format)
  • Use the wikify widget before use
\define each-other-level(filter)
{{{ [<currentTiddler>format:titlelist[]] }}}
<$list filter="$filter$">
   <<each-other-level $filter$>>
</$list>
\end
\define first-level(filter)
<$list filter="$filter$">
   <<each-other-level $filter$>>
</$list>
\end

Start in HelloThere<br>
<$tiddler tiddler="HelloThere">

<$wikify name=all-members text="""<<first-level "[is[current]tagging[]]">>""">

<<all-members>>

</$wikify>

</$tiddler>
  • We could add a parameter for the root tiddler rather than use current tiddler.
  • How you plan to use this variable list of titles will influence how you reference it.

And we can add whitespace trim

\define each-other-level(filter)
\whitespace trim
{{{ [<currentTiddler>format:titlelist[]] }}}
<$list filter="$filter$">
   <<each-other-level $filter$>>
</$list>
\end
\define first-level(filter)
\whitespace trim
<$list filter="$filter$">
   <<each-other-level $filter$>>
</$list>
\end

Start in HelloThere<br>
<$tiddler tiddler="HelloThere">

<$wikify name=all-members text="""<<first-level "[is[current]tagging[]]">>""">

<<all-members>>

</$wikify>

</$tiddler>

@TW_Tones: Thanks for all your work.
But like I said before, the kin filter is too slow for a large wiki, I don’t like manually assembling a title list from a list of titles, and don’t get me started on $wikify which I believe is generally discouraged and should be avoided if possible.
Also, I need to assign the whole title list to a variable or use it as an iterator for a $list widget, not just print it out. That would further complicate things.

I whipped together (or rather copy-pasted) a new recursive filter operator that I will post in a new thread momentarily, so that others may find it should they look for something similar.

Have a nice day
Yaisog

PS: I have posted the new filter operators in a new topic.