How to convert a numeric list into a character one?Hi everybody,
I have a list containing numbers and I would like to transform them into characters. Is there a way to do that without using a loop? I was not able to find the proper function.
Thanks for your help!
Data Blending and CleanupRe: How to convert a numeric list into a character one?@DonMcCormack The vanilla for-loop is both fastest, and slowest, depending on problem size. I'm really surprised @ms the words-based solution performs so well at large sizes. I really like the unexpected answers that showcase a feature in JMP like that. I'm a bit surprised for-each is faster than for, at some size. I like knowing that too.
I would not try to avoid anything. I like your current plan for a discussion, rather than a clear winner. Here are some discussion starter ideas:
- If you had N lists to convert, and they all had M elements, how do N and M affect the code you would write? Consider not just speed, but correctness and ease of maintenance.
- Which ideas seem best for memory constrained machines?
- How would you show "NaN" rather than "."?
- What would a general purpose routine look like? What would you call it if it was built in to JMP?
Re: How to convert a numeric list into a character one?There's also Transform Each, which appears to be a little faster than For Each here.
theList = Transform Each( {value}, theList, Char( value ) );
Re: How to convert a numeric list into a character one?Thanks @Craige_Hales ! I like it. Let me see if I can work it into the next Challenge. Should we try to avoid any iteration or just For (and its derivatives)? One way of avoiding iteration is through expression evaluation. If you're unfamiliar with this approach, check out @joseph_morgan 's Discovery tutorial, point 1. For the above problem, the function might look something like this:
convertNumberToCharacter = Function({inList},{i=1,outList={}},
outList[1::N Items(inList)] = Expr(Char(inList[i++]));
Eval List(outList);
);
/* You can check it out using the code below.
tStart = HP Time();
alist = As List(J(10000,1,Random Normal(1e6,1e5)));
newList = convertNumberToCharacter(alist);
Print((HP Time()-tStart)/1e6);
*/
I have tried this in a few of the Challenges and, while succinct, tends to take longer and is harder to understand (unless you are fairly familiar with expression handling).
Re: How to convert a numeric list into a character one?@DonMcCormack- Challenge!
Re: How to convert a numeric list into a character one?Wow I was looking for one solution and I got so many! JMP is amazing! Thanks all of you!
Re: How to convert a numeric list into a character one?Nice illustration of the size-dependent performance of the different functions. I'm still using JMP 15 and can't use For Each() yet, but to extend Jeff's timing exercise further I toss in two more functions that give the same result.
Repeat(k = 0; {k++; Char( theList[k] )}, listsize);
Words( Substr( Char( theList ), 2, Length( Char( thelist ) ) - 2 ), ", " );

The For loop, which is the fastest for small lists, is surpassed by Words at size>50, by the data-table-detour function at size>1000 and by Repeat at size>30000.
I was a little surprised to see that Words remained the fastest for size>50, about twice as fast at millions of "words".
Re: How to convert a numeric list into a character one?Thanks for the additional information @Jeff_Perkinson and @Craige_Hales !
We always learn a lot of things with the Community!!
Re: How to convert a numeric list into a character one?Extending Jeff's answer
Different overheads hurt for small sizes and help for large sizes.Different overheads hurt for small sizes and help for large sizes.Different overheads hurt for small sizes and help for large sizes.
dt = New Table( "Untitled 3",
Add Rows( 0 ),
New Column( "size", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "for", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "foreach", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "custom", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) )
);
NumListToChar = Function( {myList},
{defaultlocal},
dtx = New Table( "x", New Column( "y", values( myList ) ), private );
dtx:y << data type( character );
myList = dtx:y << get values;
Close( dtx, nosave );
Return( myList );
);
For( listsize = 1, listsize < 1e7, listsize *= 2,
theList = As List( J( listsize, 1, Random Integer( 100 ) ) );
start = HP Time();
For Each( {value, index}, theList, theList[index] = Char( value ) );
foreachloop = HP Time() - start;
theList = As List( J( listsize, 1, Random Integer( 100 ) ) );
start = HP Time();
theList = NumListToChar( theList );
customfunction = HP Time() - start;
theList = As List( J( listsize, 1, Random Integer( 100 ) ) );
start = HP Time();
For( i = 1, i <= N Items( theList ), i++,
theList[i] = Char( theList[i] )
);
forloop = HP Time() - start;
Show( foreachloop, customfunction, forloop );
dt << addrows( 1 );
dt:size[N Rows( dt )] = listsize;
dt:for[N Rows( dt )] = forloop / 1e6;
dt:foreach[N Rows( dt )] = foreachloop / 1e6;
dt:custom[N Rows( dt )] = customfunction / 1e6;
Wait( 0.1 ); // so it shows on display
);Re: How to convert a numeric list into a character one?Here's a quick timing program for the three methods, for loop, for each, and custom function using data table.
Names Default To Here( 1 );
listsize=1000000;
theList = As List( J( listsize, 1, Random Integer( 100 ) ) );
NumListToChar = Function( {myList},
{defaultlocal},
dtx = New Table( "x", New Column( "y", values( myList ) ), private );
dtx:y << data type( character );
myList = dtx:y << get values;
Close( dtx, nosave );
Return( myList );
);
start = HP Time();
For Each( {value, index}, theList, theList[index] = Char( value ) );
foreachloop = HP Time() - start;
theList = As List( J( listsize, 1, Random Integer( 100 ) ) );
start = HP Time();
theList = NumListToChar( theList );
customfunction = HP Time() - start;
theList = As List( J( listsize, 1, Random Integer( 100 ) ) );
start = HP Time();
For( i = 1, i <= N Items( theList ), i++,
theList[i] = Char( theList[i] )
);
forloop = HP Time() - start;
show(foreachloop, customfunction, forloop);
For me with the listsize shown above the results are very similar between the three methods:
foreachloop = 1106974;
customfunction = 1077862;
forloop = 1400643;
Re: How to convert a numeric list into a character one?Thanks @Jeff_Perkinson !
I did some simulations just by curiosity to compare the execution time of each solution and it seems that the for each function is on average the fastest one!
So I am gonna pick that one although the function of @txnelson also works very well.
Thanks to both of you 
Re: How to convert a numeric list into a character one?New in JMP 16 is the For Each() function which iterates over a container – list, matrix, or associative array – to perform an operation on each element.
Here is an example to show how to use it to convert your list of numbers to a list of character strings.
Names Default To Here( 1 );
theList = {7, 8, 9};
For Each( {value, index}, theList, theList[index] = Char( value ) );
Re: How to convert a numeric list into a character one?Thanks for your answer @txnelson it is indeed what I was looking for.
I just wonder what is the faster between a loop and a function which involves table creation. Any idea?
Re: How to convert a numeric list into a character one?Here is a little script that creates a function that does what you want. You can either define and use the function in your code, or use the 4 statements in open code to do the conversion.
Names Default To Here( 1 );
theList = {7,8,9};
NumListToChar = Function( {myList},
{defaultlocal},
dtx = New Table( "x", New Column( "y", values( myList ) ), private );
dtx:y << data type( character );
myList = dtx:y << get values;
Close( dtx, nosave );
Return( myList );
);
theList = NumListToChar( theList );