Needed: specific List Concatenation Logic

I have a list with varying length elements in it.
I am looking for a way to convert it into a string of a specific length without breaking up the various length elements into pieces. In other words, concatenate them back to back, but keep the elements whole.

The index is the last element number that was included in the output.
Data is the string result.

I created a recursive code that does it in a way, but was wondering if there was a HOF magic that could do it faster or more elegantly using the keep/map/combine magic.

Here is my sample input table:

Here is the output:

Here is my code:

Thanks

Not elegant but a nice exercise :slight_smile:
V1

<block s="evaluate"><block s="reifyReporter"><script><block s="doDeclareVariables"><list><l>sublist</l><l>last index</l><l>temp</l></list></block><block s="doSetVar"><l>sublist</l><block s="reportNewList"><list></list></block></block><block s="doSetVar"><l>last index</l><l>0</l></block><block s="doSetVar"><l>temp</l><block s="reportMap"><block s="reifyReporter"><script><block s="doIf"><block s="reportLessThan"><block s="reportStringSize"><block s="reportJoinWords"><block var="sublist"/></block></block><l>40</l></block><script><block s="doAddToList"><block var="value"/><block var="sublist"/></block><block s="doChangeVar"><l>last index</l><l>1</l></block></script></block><block s="doReport"><l></l></block></script><list><l>value</l></list></block><block var="data"/></block></block><block s="doReport"><block s="reportNewList"><list><block var="last index"/><block s="reportJoinWords"><block var="sublist"/></block></list></block></block></script><list><l>data</l></list></block><list><block s="reportNewList"><list><l>R010064</l><l>E9</l><l>RDE0004</l><l>RE90003</l><l>RD0001B</l><l>E9</l><l>E9</l><l>E4</l><l>DE</l><l>DE</l><l>DC</l><l>E4</l><l>R010CF4</l><l>E9</l></list></block></list></block>

V2 that removes the temp by further "cheating" :slight_smile:

image

V3 Just discovered that I can place my script directly inside the keep items block so removes the need for the extra map

image

V4 - much better as doesn't contain any "cheating" :slight_smile:

image

I'll be spending next few hours/days trying to understand Brian's solution :slight_smile:

Well, first of all, since the recursive call is a tail call, it's equivalent to a loop, and you could write this with neither recursion nor HOFs if you want.

HOFs are at their best when the processing of each item is independent of the rest of the list, and that's not the case here. So any purely HOF solution is likely to be a little kludgy.

But your problem reminds me that we're missing a list tool, which probably has a standard name that I'm spacing on, namely a variant of COMBINE that reports a list of partial sums or products or whatever:



(I wouldn't really implement it that way; it's very inefficient. But it's good enough for demonstration purposes.)

With that tool we can do it this way:


Of course the first three SETs could be replaced by a big composition:

and the call to INDEX OF wouldn't be necessary if I weren't an idiot and had specified FIND FIRST ITEM to report the index of the item it finds rather than the value itself. (It's too late to change that, because FIND FIRST is used all over BJC now, but maybe, Jens, we should make a new primitive FIND INDEX OF FIRST or something? Hideous name, I know, but we could improve that.)

If the input list is really long, I'd worry about the inefficiency of computing the partial sums all the way to the end of the list and then ignoring all the ones bigger than the desired length. So I'd use streams or something.

V5 I think this is a simple as I can get it

image

Are You sure, that it stops when there is no enough data? There is no check for empty "list".
Also, it finds first result longer or equal to length. Is this intended?

V5a1 Bit more robust than V5

image

Considering
combine script pic (1)
what is expected as a result for empty list.

You consider 1 as a valid output of such function. First intermediary result during "combine" is item(1) x item(2). Is there any case when lambda is evaluated for the first element alone? So really first input is unconditionally added to the output.
But if You insists...
combine script pic (5)

BTW. Why scalar can't be coerced to single element list where applicable? So creating list by adding element to scalar will be possible. And length and emptiness can be tested without type safeguards.

Second: there is something wrong with
combine script pic (3)

:slight_smile:
...........

As to OP problem. Maybe something like this
combine script pic (6)
Used this way
combine script pic (7)
It reports result shorter then the max len.
Of course to avoid duplicate "joining" extra helper variable can be used. Also there is one more extra item scanned in case result length == len.

No, that's a feature. For an empty list, COMBINE should report the identity element for the given operation. Luckily there are only a handful of operations that people use with COMBINE so we taught it the identity elements for all of them.

That's an interesting idea. My only concern is that if the user gets accustomed to programming that way and then writes a program that uses heterogeneous data, in which once in a while a datum is a list -- for example, it's representing some abstract data type such as Point (list x y) -- and the result is unexpectedly flattened.

Meanwhile, the behavior you want is provided by the SENTENCE block in the words/sentences library, which I keep trying to convince Jens to add as a primitive. In the word/sentence context, flattening is desirable. :~)

Wow!
I have to spend a day studying all these interesting suggestions. Some of them I doubt if I will grasp.
But thanks all of you for taking the time to indulge me.

These are missing:
and (true)
or (false)

Yup, good call! Thanks.