Artur Castiel
Artur Castiel

Reputation: 185

Extract data from a Cell Array using a vector and converting into an array

I have a cell array [5x1] which all cells are column vectors such as:

exInt =

    [46x1 double]
    [54x1 double]
    [40x1 double]
    [51x1 double]
    [ 9x1 double]

I need to have a vector (vec) containing the cells in extInt I need to extract and then I have to convert these into a single column array. Such as:

    vec = [1,3];
    Output = cell2mat(extInt{vec})

Output should become something an array [86x1 double].

The way I have coded I get:

Error using cell2mat
Too many input arguments.

If possible, I would like to have a solution not using a loop.

Upvotes: 0

Views: 1199

Answers (4)

Suever
Suever

Reputation: 65430

The best approach here is to use cat along with a comma-separted list created by {} indexing to yield the expected column vector. We specify the first dimension as the first argument since you have all column vectors and we want the output to also be a column vector.

out = cat(1, extInt{vec})

Given your input, cell2mat attempts to concatenate along the second dimension which will fail for your data since all of the data have different number of rows. This is why (in your example) you had to transpose the data prior to calling cell2mat.

Update

Here is a benchmark to compare execution times between the cat and cell2mat approaches.

function benchit()

    nRows = linspace(10, 1000, 100);

    [times1, times2] = deal(zeros(size(nRows)));

    for k = 1:numel(nRows)

        rows = nRows(k);

        data = arrayfun(@(x)rand(randi([10, 50], 1), 1), 1:rows, 'uni', 0);
        vec = 1:2:numel(data);

        times1(k) = timeit(@()cat_method(data, vec));

        data = arrayfun(@(x)rand(randi([10, 50], 1), 1), 1:rows, 'uni', 0);
        vec = 1:2:numel(data);

        times2(k) = timeit(@()cell2mat_method(data, vec));
    end

    figure

    hplot(1) = plot(nRows, times1 * 1000, 'DisplayName', 'cat');
    hold on
    hplot(2) = plot(nRows, times2 * 1000, 'DisplayName', 'cell2mat');

    ylabel('Execution Times (ms)')
    xlabel('# of Cell Array Elements')

    legend(hplot)
end

function out = cat_method(data, vec)
    out = cat(1, data{vec});
end

function out = cell2mat_method(data, vec)
    out = cell2mat(data(vec)');
end

enter image description here

The reason for the constant offset between the two is that cell2mat calls cat internally but adds some additional logic on top of it. If you just use cat directly, you circumvent that additional overhead.

Upvotes: 4

NLindros
NLindros

Reputation: 1693

You have a small error in your code

Change

Output = cell2mat(extInt{vec});

to

Output = cell2mat(extInt(vec));

For cells, both brackets and parentheses can be used to get information. You can read some more about it here, but to summarize:

  • Use curly braces {} for setting or getting the contents of cell arrays.
  • Use parentheses () for indexing into a cell array to collect a subset of cells together in another cell array.

In your example, using brackets with index vector vec will produce 2 separate outputs (I've made a shorter version of extInt below)

extInt = {[1],[2 3],[4 5 6]};
extInt{vec}
ans =
     1
ans =
     4     5     6

As this is 2 separate outputs, it will also be 2 separate input to the function cell2mat. As this function only takes one input you get an error.

One alternative is in your own solution. Take the two outputs and place them inside a new (unnamed) cell

{extInt{vec}}
ans = 
    [1]    [1x3 double]

Now, this (single) result goes into cell2mat without a problem. (Note though that you might need to transpose your result before depending on if you have column or row vectors in your cell. The size vector (or matrix) to combine need to match/align.)

Another way as to use parentheses (as above in my solution). Here a subset of the original cell is return. Therefore it goes directly into the cell2matfunction.

extInt(vec)
ans = 
    [1]    [1x3 double]

Upvotes: 3

ben
ben

Reputation: 1390

use

 Output = cell2mat(extInt(vec))

Since you want to address the cells in extInt not the content of the cells

extInt(vec)
extInt{vec}

try those to see whats going on

Upvotes: 0

Artur Castiel
Artur Castiel

Reputation: 185

I have been messing around and I got this working by converting this entry into a new cell array and transposing it so the dimensions remained equivalent for the concatenating process

Output = cell2mat({extInt{vec}}')

Upvotes: 0

Related Questions