3

I need to build an array of objects of class ID using arrayfun:

% ID.m
classdef ID < handle
    properties
        id
    end
    methods
        function obj = ID(id)
            obj.id = id;
        end
    end
end

But get an error:

>> ids = 1:5;
>> s = arrayfun(@(id) ID(id), ids) 
??? Error using ==> arrayfun
ID output type is not currently implemented.

I can build it alternatively in a loop:

s = [];
for k = 1 : length(ids)
    s = cat(1, s, ID(ids(k)));
end

but what is wrong with this usage of arrayfun?

Edit (clarification of the question): The question is not how to workaround the problem (there are several solutions), but why the simple syntax s = arrayfun(@(id) ID(id), ids); doesn't work. Thanks.

Amro
  • 123,847
  • 25
  • 243
  • 454
Serg
  • 13,470
  • 8
  • 36
  • 47

3 Answers3

5

Perhaps the easiest is to use cellfun, or force arrayfun to return a cell array by setting the 'UniformOutput' option. Then you can convert this cell array to an array of obects (same as using cat above).

s = arrayfun(@(x) ID(x), ids, 'UniformOutput', false);
s = [s{:}];
robince
  • 10,826
  • 3
  • 35
  • 48
  • 1
    Thanks, but it seems as a patch, like the loop method. My question was why `arrayfun(@(id) ID(id), ids)` doesn't work. Is it a Matlab's bug, or wrong usage? – Serg Jun 05 '12 at 14:03
  • as I sometimes miss the python functionality to endlessly extend commands, and frequently use your cell to array construction I often declare an anonymous function to do it in one go: `dealcell = @(x)x{:};`, which can then be used like `s = [dealcell(arrayfun(...))];` – hugovdberg Jan 05 '15 at 08:21
  • You need `s = reshape(s, size(ids))` to make that truly match `arrayfun` – Eric May 12 '17 at 17:20
3

You are asking arrayfun to do something it isn't built to do.

The output from arrayfun must be:

scalar values (numeric, logical, character, or structure) or cell arrays.

Objects don't count as any of the scalar types, which is why the "workarounds" all involve using a cell array as the output. One thing to try is using cell2mat to convert the output to your desired form; it can be done in one line. (I haven't tested it though.)

s = cell2mat(arrayfun(@(id) ID(id), ids,'UniformOutput',false));
tmpearce
  • 12,523
  • 4
  • 42
  • 60
  • 3
    actually CELL2MAT will fail with the error `Cannot support cell arrays containing cell arrays or objects.` – Amro Jun 05 '12 at 22:23
  • @Amro Ah, interesting. Thanks for pointing that out, like I said I hadn't tested it. Is there a way to get handles to the objects into a vector? – tmpearce Jun 05 '12 at 22:26
  • you can create object arrays (I posted an answer), just not with ARRAYFUN. In fact ARRAYFUN can *iterate* over array of objects (as input), just not return them as output (must return scalars of cells as you pointed out). You can also do it as @robince showed – Amro Jun 05 '12 at 22:37
2

This is how I would create an array of objects:

s = ID.empty(0,5);
for i=5:-1:1
    s(i) = ID(i);
end

It is always a good idea to provide a "default constructor" with no arguments, or at least use default values:

classdef ID < handle
    properties
        id
    end
    methods
        function obj = ID(id)
            if nargin<1, id = 0; end
            obj.id = id;
        end
    end
end
Amro
  • 123,847
  • 25
  • 243
  • 454