Trying to sum up the number holding fields of tiddlers that are listed in the field of another

Hello there!

I have a tiddler with a field named after the variable <adv>, in a dictionary tiddler named after the variable <advbook>. The <adv> field holds the name of other tiddlers sometimes followed by a number, sometimes not, each separated by a comma:

Song, Dance 2, One College Only

Each of those tiddlers (not the numbers) have a field named modifier-value.

I’m trying to sum up all the modifier-value of those. I’m going for a two-prong approach:

  1. first summing up those tiddlers whose name isn’t followed with a number,
  2. then those that are (for these I need another formula multiplying the number by another field called modifier-per-level-value).

I’m stumbling on the 1. already with that approach:

<$set name="unlevelablesvalues" filter="[<advbook>get<adv>split[, ]!regexp[\d+$]]:map[get[modifier-value]]">unlevelablesvalues: (<<unlevelablesvalues>>)
<$list filter="[<unlevelablesvalues>split[ ]] +[sum[]]" variable="unlevelableSum">(Sum of unlevelables: <<unlevelablesSum>>) </$list></$set>

Thanks to the little debug parts, I saw that the $set widget does the job I intended it to do, outputing a list of the form [-40 -40 -40]. However, the $list widget returns 0. I’m guessing my filter run on the list established by the $set widget is wrong.

Can somebody explain to me why? Thanks in advance :slight_smile:

Update: Fixed, as often, just a typo in the name of the variables -_-'

Now unto 2., it’s becoming even more difficult. Maybe it’s actually impossible.

I have two elements to consider: the modifier itself (Dance in the above example, that is a tiddler with a modifier-per-level-value field), and the number that represent the level the modifier has (2 in this example).

Because of the fact that, to my knowledge, there is no mechanic in TW to increment or decrement a list-declared variable as the filter run happens, nor can one declare multiple variables in a <$list> widget, I tried the following work around which goal’s to basically:

  1. do a first filter run to assign the modifier variable,
  2. inside this first filter, for each step of filter run, assign the variables modname, modlevel, and modmultiplier via the <$let> widget,
  3. then use <$set> widget to run through the same list again in order to sum the products of modlevel and modmultiplier for all the modifiers the list runs through :
\procedure lvl-mods-sum(advbook, adv)
<$list filter="[<advbook>get<adv>split[, ]regexp[\d+$]]" variable="modifier" join=", ">
	<$let modname={{{ [<modifier>split[ ]butlast[]join[ ]] }}} modlevel={{{ [<modifier>split[ ]last[]] }}} modmultiplier={{{ [<modname>get[modifier-per-level-value]] }}}>
		<$set name="levelablesSum" filter="[<advbook>get<adv>split[, ]regexp[\d+$]<modevel>multiply<modmultiplier>] +[sum[]]">(levelablesSum: <<levelablesSum>>)</$set>
	</$let>
</$list>
\end

Which returns 0. (I know it would return the result once for every modifier number found in the list run, but I’m so desperate to at least get that result that I thought I’d deal with that later :sweat_smile:)

I’ve attacked that problem from multiple approaches already, and it seems that it’s just impossible to look at all the tiddlername number couples in a list, fetch from each tiddlername the value of one of their fields, multiply it by number, and return the sum of all those products.

At this stage, I’d take any suggestion, including creating temporary data tiddlers to store the stuff I need and ultimately return that result, which is the only avenue I haven’t fully explored yet. Perhaps there is a way to iterate that list of modifiers, and create a temporary dictionary tiddler holding all the modifier level:modifier multiplier pairs, then use that to get the sum of products of key/value pairs I’m after?

Through filters, (nearly) all things are possible. :wink:

I’m not at my computer right now and Discourse is trying very hard to hide my keyboard (?), but take a look at the :map filter run prefix. I think you ought to be able to use it to transform each title, then finish with a +[sum[]] outside the :map filter run.

If you can’t figure it out, poke me and I’ll come back to this. :slight_smile:

I’m aware of the map filter, which is indeed very handy for substituting the titles with the value of their field I need. But I’m stumped at the multiply all pairs, THEN sum the results part.

Unless something like this is possible>

<$list filter="[<advbook>get<adv>split[, ]regexp[\d+$]butlast[]] :map[get[modifier-per-level-value]multiply[????]] +[sum[]]" variable="modperlvlvalue">

(I wouldn’t know how to get the numbers back for the multiply though).

Or perhaps:

\procedure lvl-mods-sum(advbook, adv)
<$list filter="[<advbook>get<adv>split[, ]regexp[\d+$]butlast[]] :map[get[modifier-per-level-value]]" variable="modperlvlvalue">
<$set name="levelablesSum" filter="[<modperlvlvalue>multiply[<advbook>get<adv>split[, ]regexp[\d+$]last[]]] +[sum[]]">(levelablesSum: <<levelablesSum>>)</$set>
</$list>
\end

But that wouldn’t work either because, again, the multiply would not kow what number to multiply with since I’m giving it a list of numbers rather than an actual number…

I can produce two lists, one with every modifier modifier-per-level-value fields (let’s say -10 5 10 -20 40), and another with all their level (let’s say 0 2 2 3 1), but multiplying each entry one by one then summing the results is tying my braincells in knots.

First, a general cautionary note: You’re still trying to “nest” filter runs, as in [<modperlvlvalue>multiply[<advbook>get<adv>split[, ]regexp[\d+$]last[]]]. TW doesn’t support this kind of structure; you need to either order them such that the simple variable factor comes second:

[<advbook>get<adv>split[, ]regexp[\d+$]last[]multiply<modperlvlvalue>]

or separate them into multiple filter runs:

[<modperlvlvalue>] [<advbook>get<adv>split[, ]regexp[\d+$]last[]] +[product[]]

or use a function to store any complex factors as a single variable:

\function mod.level() [<advbook>get<adv>split[, ]regexp[\d+$]last[]]

[<modperlvlvalue>multiply<mod.level>]

Moving on to your question: it’s a little tricky to work through it in the abstract, but I’d try this sort of approach.

\function multiply.values()
[<currentTiddler>split[ ]butlast[]join[ ]get[modifier-per-level-value]]
[<currentTiddler>split[ ]last[]regexp[\d+]else[1]]
+[product[]]
\end

<$list filter="[<advbook>get<adv>split[, ]regexp[\d+$]] :map[multiply.values[]] +[sum[]]" variable="sum">
	<<sum>>
</$list>

(The regexp[\d+]else[1] step of the function filter run is technically redundant here, since you’re using regexp[\d+$] to filter the initial inputs; I included it just as an example of providing a fallback value.)

Assuming [<advbook>get<adv>split[, ]regexp[\d+$]] contains both the tiddler whose field should be retrieved and the number to be multiplied, we can use the :map/function combination to retrieve both parts of each pair and then multiply them. Apologies in advance if I’m misunderstanding your data structure!

Ok. First, don’t apologize for any misunderstanding because your didn’t misunderstand anything and your availability and quality of help is a blessing for which I have half a mind to pickup stonecarving and erect a statue to your glory :stuck_out_tongue_winking_eye:

Second, I remained completely oblivious to the existence of the Product filter prefix, which is quite stupid considering I knew about the Sum one. DUH

Third, your code works (as usual):

Fourth, all that remains for closing this whole viewTemplate feature is to finally sum the unlevelables with the levelables, but rather than doing that now, I’ll be forsaking the unlevelable modifiers by simply ALWAYS providing a level, which will be 0 for unlevelables, so that I can use the exact same operation on all the elements of the list rather than doing two separate things :slight_smile:

THANK YOU! (I have learned so much on TW thanks to you, it’s exhilirating)

If you still have the time and desire to patch my own ineptitude, I have the next problem lined up posted in the forums and which, I believe, is trickier problem to solve.

2 Likes