Compose Yourself!

Even if we crunch numbers a lot, there are plenty of times, for example, when reporting, that we need to mix numbers into text. For a very long time, we've been able to create a character vector, and more recently, a string, with functions like sprintf. Look here for more information on character arrays and strings.

That's fine if we want to create one textual entity, but what if I need an array of them? I can use sprintf in a loop, or I can use a newer function, compose. Let me show you a bit how they each work.

Contents

A Single Numeric Input

Let's create some numeric values to use as possible inputs.

nums = [exp(1) pi]

nums =
2.7183    3.1416


Here's character output from sprintf:

cs1 = sprintf('%d', nums(2))

cs1 =
'3.141593e+00'


And here's the equivalent string output:

ss1 = sprintf("%d", nums(2))

ss1 =
"3.141593e+00"


Now let's try compose:

cc1 = compose('%d', nums(2))

cc1 =
1×1 cell array
{'3.141593e+00'}

sc1 = compose("%d", nums(2))
% What do we have in our workspace?
whos

sc1 =
"3.141593e+00"
Name      Size            Bytes  Class     Attributes

ans       1x4                 8  char
cc1       1x1               136  cell
ccm1      1x2               272  cell
cs1       1x12               24  char
csm1      1x26               52  char
nums      1x2                16  double
sc1       1x1               174  string
scm1      1x2               252  string
ss1       1x1               174  string
ssm1      1x1               206  string
tc        1x1               120  cell
tmpc      1x2               228  cell
tmps      1x2                 4  char
ts        1x2                 4  char



What you may notice is that both sprintf and compose give the same output for the string version. However, for the character output, we get one character array using sprintf, but that same array embedded in a cell using compose.

clearvars -except nums


Multiple Numeric Inputs

Now let's see what happens if we are formatting output with more than a single numeric input.

csm1 = sprintf('%d ',nums)
ssm1 = sprintf("%d ",nums)
ccm1 = compose('%d',nums)
scm1 = compose("%d",nums)

csm1 =
'2.718282e+00 3.141593e+00 '
ssm1 =
"2.718282e+00 3.141593e+00 "
ccm1 =
1×2 cell array
{'2.718282e+00'}    {'3.141593e+00'}
scm1 =
1×2 string array
"2.718282e+00"    "3.141593e+00"

whos

  Name      Size            Bytes  Class     Attributes

ccm1      1x2               272  cell
csm1      1x26               52  char
nums      1x2                16  double
scm1      1x2               252  string
ssm1      1x1               206  string



What we see is that we get exactly the same types of output as before. But for the string version with compose, we get output matching the dimensions of the input, in this case, 1x2, whereas with the sprintf version, we get a single array for all of the cases. sprintf always produces a single array as output and recycles the hole (the formatter) while there is more data to format. compose returns arrays of text.

Handling Holes

Again, sprintf produces one output, regardless of the dimensions of the input.

tmps = sprintf('%d',[1 2])
tmpc = compose('%d',[1 2])

tmps =
'12'
tmpc =
1×2 cell array
{'1'}    {'2'}


Also, sprintf truncates a hole if you don’t provide data. compose leaves it there in case you want to fill it with a subsequent call:

ts = sprintf('\n %s')

tc = compose('\n %s')

ts =
'
'
tc =
1×1 cell array
{'↵ %s'}