8 Replies Latest reply on Nov 2, 2015 3:43 PM by user19752

# Recursive custom function... a task I'm trying to get my head around it

I have given myself a task.

I am attempting to create a recursive custom function to do the following:

Take a word like this:

Peter Windle

and change it to something like this :

P:e:t:e:r: :W:i:n:d:l:e

where the ":" is separating each character within the text, so in affect, I want to grab each character in the field, one at a time, until the end of the text. I have a reason for this, but I will reveal that later ! ;-)

I've looked at many samples of recursive functions, but I have not really found a solution, partly because I am still trying to get my head around the recursive functionality and partly because other examples are not quite the same as what I'm aiming for.

Any hints, suggestions, solutions?

• ###### 1. Re: Recursive custom function... a task I'm trying to get my head around it

I've been there, and I'm not quite a recursive Jedi, but here's my sample. I use a temp parameter to store the result, you can do without, but it helps to understand.

PeterWindle ( text ; sep ; temp )

// temp should be empty when invoking the function

If(not IsEmpty(text);

Let(

[

letter=Left(text;1);

new_text=Right(text;Length(text)-1);

temp=List(temp;letter)

];

PeterWindle(new_text;sep;temp)

)

;

Substitute(temp;"¶";sep)

)

PeterWindle ( "Peter Windle" ; ":" ; "" )

Here's the reasoning, you always need a way to end the recursion, and a way to make it process.

In that case that's both done via the transformation of the text, into a shorter text called new_text. That's the one we'll pass to the next call of the function. So each tile we iterate, we make a call with a one character less text the the one from the start.

We chez if text (i.e. new_text) is not empty, if it is, that means we're done and that we can display the result.

You'll also remark that rather than make the result (i.e. temp) with temp&sep&char, I prefer to use the list function and do it in the end, that's because the list function, will not insert a separator at the end or the start. So in the end I just need to substitute (If the text is huge it's faster to avoid the list)

• ###### 2. Re: Recursive custom function... a task I'm trying to get my head around it

Hi Peter,

You have a very good explanation and a neat function from Vincent. But I was working on my own function to answer your post. I am posting it anyway.

It is exactly the same principle as vincent, minus the cleverness of using the list. The only upside of using this one rather than Vincent's is that you can begin the text transformation at any position. Example : AddColonsToText ( "Test"; ""; 1 ) gives "T:e:s:t" and  AddColonsToText ( "Test"; ""; 2 ) gives you "Te:s:t".

Function : AddColonsBetweenChars ( Input; Output; Start )

Let (

[

~remainingChars = Length ( input ) - Start;

~output = Case (

~remainingChars >= 0;

Output &

Middle ( Input; Start; 1)  &

Case ( ~remainingChars > 0; ":"; "")  &

AddColonsBetweenChars ( Input; Output; Start + 1 );

Output

)

];

~output

)

Take care.

Karim

• ###### 3. Re: Recursive custom function... a task I'm trying to get my head around it

Here's my solution.

I think unlike the others submitted so far, mine uses "tail recursion" which for FileMaker recursive functions should allow it to handle longer more depth of recursion and thus longer character strings (i.e. 30,000 in length instead of just 10,000).  Tail recursion is implemented when the function is called recursively only at the very end of the calculation (the tail).  (Karim's solution may be tail recursive.)

This function allows the caller to provide a separator and it makes no restriction on the separator nor the text it operates on.  It might be a single character (including ¶), a long string, or the empty string.

-Tom

/* */

/* text: the text you want transformed */

/* sep: the character (or characters) that you want added between every character of text */

Let(

[

tL=Length(text)

];

Case(

tL = 0 ; "";

tL = 1; text;

Left(text; 1) & sep & AddSepChar(Right(text; tL-1); sep)

)

)

• ###### 4. Re: Recursive custom function... a task I'm trying to get my head around it

Like Vincent, I'll provide some conceptual information about how to approach

and solve the problem using a recursive custom function.  Peter, the following discussion

might be to basic for your level, but it might be helpful for others getting started in it.

While this specific task is fairly simple and the recursive function I provided is pretty

short to pick apart and decipher, sometimes it helps to have some guidance on where

to start when trying to solve a new problem.  It also helps to have a sense of when

recursion is the right tool for the job.

A task that lends itself to recursion generally follows the structure of

"I know how to do a little bit, and the task that remains is essentially the

same problem I started with just a little smaller."

A recursive function needs:

(1) A very reliable way to know when to stop.

(2) A way to solve the task a little and generate a smaller task that looks just like the first.

Let's apply this to the task you presented: take a string and insert a colon between every character

in the string. "apple" becomes "a:p:p:l:e".

Study the problem in the boundary conditions or the hard cases.

What do you do if there is no input?  What about only one character?

"" becomes "".  Nothing to do.

"e" becomes "e". Nothing special to do.

If I make the problem smaller, then I've got my stopping conditions from those above.

How do I make the task smaller?

If I were solving the problem by hand, I'd start at the beginning and write the first letter followed

by the colon. "a:".  Phew.  All that is left ahead of me is to tackle "pple".  Again continuing

by hand, I know that when I solve it, I'll need to write the remainder of the solution immediately

following the part I just solved.

"a:" & Solution to ("pple")

I have just found the heart of the recursion.

Implementing in FileMaker usually involves a Case() statement.

Make sure you have accommodated every situation that your function arguments might encounter even

if the input value makes no sense for the problem you are solving.

What happens if an input string of text is empty? What about an input number being negative or zero?

If you can manage it, make the recursive function call (the function's call to itself),

the very last operation in your function so that you can take advantage of the greater stack depth

available for tail recursion, i.e. your function can call itself more times to handle larger depth

problems.

-Tom

• ###### 5. Re: Recursive custom function... a task I'm trying to get my head around it

Hi Peter,

although others have made excellent suggestions here I would like to give you my solution as well:

Custom Function: Colonize ( text )

Let ( [

L = Length ( text ) ;

x = Middle ( text ; 2 ; L - 1 )

] ;

Case ( L > 1 ;

Left ( text ; 1 ) & ":" & Colonize ( x ) ;

text

)

)

I have stripped down the function as much as possible, so no settable separator and I chose head-recursion. It uses more memory, but when applied to shorter texts, it's also faster. Names probably won't exceed 10^4 (or even 10^2) so it should do.

Then how to create such a function:

It is just a matter of definition and your requirement happens to be really straight forward and easy:

Add a colon after each character as long as it is not the last character

and that's what happens in this function in (more or less) 2 steps:

1. The LET statement just reads the input and creates the new string for the recursive call of the function and a variable (L) for
2. a check which is done in the CASE statement and there you see the requirement from the quoted text:

As long as the length is more than 1 character, take the first character from the given text, place a colon after it and call the same function with the rest of the text.

PeterWindle wrote:

I want to grab each character in the field, one at a time, until the end of the text.

is met exactly as you've written it yourself ;-)

• ###### 6. Re: Recursive custom function... a task I'm trying to get my head around it

That's truly awesome guys...

thanks so much for everyone's help

• ###### 7. Re: Recursive custom function... a task I'm trying to get my head around it

In FM, "tail recursion" need function call without additional calculation outside of the function, so yours are not.

This is it.

/*

AddColonsBetweenChars19752 ( input ; start )

input:text

start:always 2

*/

Case ( Length ( input ) < start ; input ;

AddColonsBetweenChars19752 ( Replace ( input ; start ; 0 ; ":" ) ; start + 2 )

)

• ###### 8. Re: Recursive custom function... a task I'm trying to get my head around it

I wondered that too many recursion makes function result random value, not "?"

Is this bug of my machine? (Windows7, FM12)