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.
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:
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.
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?
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...
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.
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.