Splitting once vs multiple times

This is likely a very quick syntax question for someone in the know.

I have a working solution to my immediate problem, but I’m wondering why an alternative I would have thought to work the same but more efficiently does not work.

This works just fine, splitting an input string into three component parts:

<!-- currentTiddler is, say, "north-10-3" -->
<$let
  block={{{ [all[current]split[-]nth[1]] }}}
  cols={{{ [all[current]split[-]nth[2]] }}}
  rows={{{ [all[current]split[-]nth[3]] }}}
>
<<currentTiddler>> :: block: "<<block>>", rows: "<<rows>>", cols: "<<cols>>" 
</$let>

<!--yielding: -->
north-10-3 :: block: "north", rows: "3", cols: "10"

This one does not:

<!-- currentTiddler is, say, "north-10-3" -->
<$let
  parts={{{ [all[current]split[-]] }}}
  block={{{ [<parts>nth[1]] }}}
  cols={{{ [<parts>nth[2]] }}}
  rows={{{ [<parts>nth[3]] }}}
>
<<currentTiddler>> :: block: "<<block>>", rows: "<<rows>>", cols: "<<cols>>" 
</$let>

<!-- yielding -->

north-10-3 :: block: "north", rows: "", cols: ""

And I simply don’t understand why that is. I thought that perhaps adding enlist[] at the end of the parts filter would fix it, but if anything, it made it worse.

(I am right that if I get the filters correct, this is how <$let ...> is supposed to work right? The definitions can be based on earlier ones in the widget, right?)

Can someone explain why its wrong, and if there’s a simple way to fix it. And if possible, could you confirm whether this should actually be more performant? This is happening inside a nested loop, so I’d like to at least not be stupid about performance.

Try this to see the result:

<$let parts={{{ [[a]] [[b]] [[c]] }}}>

<<parts>>

</$let>

You will see that we only get the first element in the list.

Essentially, the thing that separates the elements in the list is the thing that is preventing “parts” from getting all of the elements.

“lists” (i.e. the result of {{{ [[a]] [[b]] [[c]] }}}) cannot be assigned to variables.

The assignment to “parts” only assigns the first element.

2 Likes

The problem is that when a filtered transclusion is used as a widget parameter value, only the first result of the filter is assigned to the parameter.

For example:
<$let something={{{ [[one]] [[two]] [[three]] }}}>
results in the variable something having a value of “one

Thus, in the first line of your $let widget, <$let parts={{{ [all[current]split[-]] }}} sets the variable parts to a value of “north”, rather than a list of three values, “north”, “10” and “3”.

To assign a list to the parts variable, you can use the $set widget, like this:

<$set name="parts" filter="[all[current]split[-]]">
<$let
  block={{{ [enlist<parts>nth[1]] }}}
  cols={{{ [enlist<parts>nth[2]] }}}
  rows={{{ [enlist<parts>nth[3]] }}}
>

Alternatively, if you don’t want to use a separate $set widget, you could write:

<$let
  parts={{{ [all[current]split[-]format:titlelist[]join[ ]] }}}
  block={{{ [enlist<parts>nth[1]] }}}
  cols={{{ [enlist<parts>nth[2]] }}}
  rows={{{ [enlist<parts>nth[3]] }}}
>

The assignment to parts splits the text at the “-” delimiters, then formats those three results by adding doubled-square brackets as needed (i.e., if a value contains spaces) and then joins all the results into a single space-separated list. This produces the same parts value as the $set widget.

Note that if you are certain that the parts will not contain any spaces, you can simplify this to just
parts={{{ [all[current]split[-]join[ ]] }}}
or even
parts={{{ [all[current]search-replace[-],[ ]] }}}

3 Likes
  • I always wondered why this were so, when a filter could be written to only return one value anyway. Of course, it is the rule now.

Ok, I’m confused as to the reason why, but it certainly explains the behavior.

That works great! I don’t really care between a separate <$set ...> and embedding them in the <$let ...>. I hadn’t used let and this simply seemed a good time to try it. (I love my let bindings in various languages, and when working in JS am very jealous of languages that do them right.)

However for those who come along later, neither of the alternatives worked for every case, even though there are no spaces. I probably applied them wrong, but that’s ok. I’m happy enough to both get this working and understand why my alternate version didn’t work.

Thank you both very much for your help!

I’m curious too, but not enough to investigate, not when I’m close to finishing my next goal on my current project.

Ok, neither did the original work properly for all cases. The problem is that three of the entries duplicate numbers, e.g. northwest-1-1, southwest-2-2 and southeast-2-2. But that means that instead of northwest 1 1, I simply get northwest 1 (with the duplicate removed.) I need to avoid that.

I know I’ve seen the solution to this before, and I’ll go try to find it myself. But I wouldn’t turn down advice! :slight_smile: (I know to start with Dominant Append.)

Anyone who wants to play with it can use these two tiddlers:

splitIssue.json (2.8 KB)

If it hasn’t been clear, this is related to the Periodic Table I’ve been working on.

1 Like

None of this is documented (that I know of), so I’ll take a crack at it in very general terms.

A variable is meant to hold a solitary value.

{{{ [[a]] [[b]] [[c]] }}} results in a list of values.

Assigning a list of values to a variable does not work because a variable can only hold one value, not a list of values.

That’s how it works.

Why it works that way, that gets likely into the theory of data structures.

The kind of data structure needed to hold one value is pretty simple and keeps the entire core simple everywhere that needs to know how to handle a variable.

The kind of data structure required to hold a list of values, that really complicates (really gums up) the machinery because it is by no means a trivial thing to have everything know how to deal with a variable that is holding a list of values.

Something like that …

1 Like

Not sure that is, true, in fact I am sure it is not, you just need a way to separate the list later.

Read up about the enlist operator’s “raw” suffix.

Also play with the following and see the results

{{{ [enlist[1 1 1]join[,]] }}} 

{{{ [enlist:raw[1 1 1]join[,]] }}}

https://tiddlywiki.com/#enlist%20Operator

2 Likes

If you join[] a list of values, it is no longer a list.

It is just one value that is a stringing of what used to be separate values and distinct elements in a list (i.e. element nth[1], element nth[2], element nth[3] …).

{{{ [[a]] [[b]] [[c]] }}} results in a list. Assign that to a variable, and the value will be equal to only “a”. Because a variable can only hold one value from one element (or item), and that is element “nth[1]”.

{{{ [[a]] [[b]] [[c]] +[join[,]] }}} is a list that has only one element (nth[1]) with value “a,b,c”. Assign that to a variable, and the variable will be equal to “a,b,c”. (The double quotes are just delimiters I’m using to highlight the values.)

But “a,b,c” is not a list. It is one value. We may think of it as a comma separated list, but to any software, that is just one value.

{{{ [[a,b,c]] }}} will yield a list of only one element (“nth[1]”) . The value of that one element is “a,b,c”.

{{{ [[a,b,c]split[,]] }}} will yield a list with three elements. One element (“nth[1]”) with value “a”, one element (“nth[2]”) with value “b”, and one element (“nth[3]”) with value “c”. The list of three elements is the result of splitting the one “value” into individual elements (with a value for each element).

Yes, thank you. I got there. But at this point, I was ready to go back to my initial, working example from the first post and not chase this down any further. The original one was simple enough. It just looked as through I should be able to make a more performant version with very little cost. The complexities mean I won’t bother for now. But thank you very much for your help. I’m learning a lot here!

It’s fun, eh?

I find the foundational TiddlyWiki stuff wildly interesting.

That’s why i’m staying on TW5.2.3. All of the new stuff coming down the pipes is just gumming up the works for me (too big of a distraction from the foundational goodies that I want to continue mastering.)

Note that the split[] operator does NOT remove duplicates. Thus
[[northwest-1-1]split[-]]
correctly results in 3 items
northwest, 1, and 1

-e

1 Like

Yes, but this was then followed by an enlist:

and I believe that then does the dominant appending. In any case, it wasn’t working, whereas my initial script without the parts variable, and with separate split invocations does work. I think from what Charlie demoed, I could use enlist:raw instead and get it to work, but if I’m going to call all these enlists anyway, it seems to gain nothing over my initial approach.

Meanwhile, I’m new enough that I’m eagerly awaiting TW5.3.0. I’ve only read the relevant threads and haven’t tried it, yet, but it looks like the new stuff is closely aligned with my own thinking. The big thing I’m working on, I will probably recast to TW5.3, as I’m sure it won’t be close to done before that version is out. My other large project – for my day job – is mostly done, and although most of the work there is simple content, I can’t see any rationale for trying to upgrade it. I’ll probably fiddle with it for several plugins I maintain and make individual calls on them, but I would love to get on it sooner rather than later.