File Exchange Pick of the Week

When Deal doesn’t work, Disperse! 2

Posted by Brett Shoelson,

Brett's Pick this week is Disperse, by Sam Hallman.

When I first saw Sam's "disperse" function--with the tagline "Assign elements of an input array to individual output variables with a single function call--" I thought, "well, that's silly! Why not just use MATLAB's deal function?" Deal lives to distribute inputs to outputs.

But fortunately for me, I read on, and came to Sam's statement: "DISPERSE is not the same as DEAL. For example, if A is a vector then [a b c d] = disperse(A) performs a=A(1), b=A(2), c=A(3), and d=A(4), whereas [a b c d] = deal(A) performs a=A, b=A, c=A, and d=A." That immediately had me thinking about all the many times over the years when I've looked to DEAL to do something it wasn't designed to do, and ended up writing for-loops, or clumsy work-around code, instead. But no longer!

Sam's code is terse, yet widely useful. It works beautifully on cell arrays:

data = {'one' [2 3] 'four' 5}
[a,b,c,d] = disperse(data)
data = 
  Columns 1 through 3
    'one'    [1x2 double]    'four'
  Column 4
    [5]
a =
one
b =
     2     3
c =
four
d =
     5

Compare that to:

[a,b,c,d] = deal(data)
a = 
  Columns 1 through 3
    'one'    [1x2 double]    'four'
  Column 4
    [5]
b = 
  Columns 1 through 3
    'one'    [1x2 double]    'four'
  Column 4
    [5]
c = 
  Columns 1 through 3
    'one'    [1x2 double]    'four'
  Column 4
    [5]
d = 
  Columns 1 through 3
    'one'    [1x2 double]    'four'
  Column 4
    [5]

DISPERSE works with the elements of structs, too, where a usage of DEAL would similarly assign the full structure to each of the outputs:

s = struct('strings', {'sam','hello'}, 'lengths', [3 5])
[a b] = disperse(s)
s = 
1x2 struct array with fields:
    strings
    lengths
a = 
    strings: 'sam'
    lengths: [3 5]
b = 
    strings: 'hello'
    lengths: [3 5]

Note that we could workaround the cell problem with this approach:

[a,b,c,d] = deal(data{:})
a =
one
b =
     2     3
c =
four
d =
     5

And for structures, we could write something like this:

sc = num2cell(s);
[a, b] = deal(sc{:})
a = 
    strings: 'sam'
    lengths: [3 5]
b = 
    strings: 'hello'
    lengths: [3 5]

But the simplified syntax and ease of use still recommends DISPERSE.

You can subset your data, extract (disperse) elements of an n-dimensional array, even extract individual color planes in an RGB image:

img = imread('peppers.png');
[r g b] = disperse(img);
% figure;
% subplot(2,2,1)
% imshow(img); title('RGB')
% subplot(2,2,2)
% imshow(r); title('Red')
% subplot(2,2,3)
% imshow(g); title('Green')
% subplot(2,2,4)
% imshow(b); title('Blue')

DISPERSE ships with an html report, generated with MATLAB's PUBLISH function, that shows lots of ways to use the function. It's thorough, and very helpful.

As always, comments to this blog post are welcome. Or leave a comment for Sam here.


Get the MATLAB code

Published with MATLAB® 7.13

2 CommentsOldest to Newest

In the first example, the data can be more succinctly distributed, at least in the more recent versions of Matlab, without the use of either DEAL or DISPERSE:

[a,b,c,d] = data{:};

This can be learned from the new help page for DEAL By the way, that help page also makes clear that many previous usages of DEAL are now unnecessary. It remains a useful function to swap or rotate variables,

[a,b,c] = deal(b, c, a);

or to initialize several variables to the same value,

[a,b,c] = deal(zeros(2,3)); % a = b = c

which a Matlab neophyte might be tempted to code (wrongly) as a = b = c = zeros(2,3).

In the second and third examples, yes, you need two lines of code, but again no need for DEAL or DISPERSE:

sc = num2cell(s);
[a, b] = sc{:};

and

ce = num2cell(imdata, 1:2);
[r,g,b] = ce{:};

Although DISPERSE leads to more succinct code in the last two examples, the readability that you gain when using instead the conversion of a comma-separated list, generated by {:}, to an array seems to be worth writing an extra short line. Reading your 3rd example, I would need to learn that DISPERSE distributes the *last* dimension of the array. In contrast, the NUM2CELL usage makes clear that the cell was formed along dimensions 1 and 2, and has therefore the length of the 3rd dimension of the image, which corresponds to the colors. To me, this clarity sounds like a good DEAL when compared to learning the details of a one-size-fits-all new function.

Hi Roberto,
You make good points for alternative syntaxes of DEAL. The num2cell approach, though, might be considered an “advanced manuever.” At least, it’s one that a lot of MATLABbers might have a hard time coming up with. I still say that DISPERSE makes some of these cases easier–to recall, and to implement.
Thanks for the thoughts!
Brett

These postings are the author's and don't necessarily represent the opinions of MathWorks.