在Matlab中何时使用cell数组或结构体比较合适?

19

如果我想要将不同大小的字符串或矩阵存储在单个变量中,我可以考虑两种选择:我可以创建一个结构体数组,并让其中一个字段保存数据。

structArray(structIndex).structField

或者我可以使用一个单元数组,

cellArray{cellIndex}

但是否有通用的经验法则来决定使用哪种数据结构?我想知道在某些情况下使用其中一种有没有缺点。

4个回答

17

在我看来,这更多是关于方便性和代码清晰度的问题。问问自己,你更喜欢通过数字还是名称来引用变量元素。如果是前者,请使用cell数组;如果是后者,请使用struct数组。可以想象一下有无标题的表格。

顺便提一下,您可以很容易地使用CELL2STRUCTSTRUCT2CELL函数在结构体和单元数组之间转换。


4
使用单元数组时,需要一些元数据来识别单元格内容。精心选择的字段名称可以使您的代码自我解释。 - zellus

10

如果您在函数内使用它进行计算,我建议您使用cell数组,因为它们更方便处理,例如通过CELLFUN

然而,如果您用它来存储数据(并返回输出),最好使用结构体,因为字段名称是(应该是)自说明的,所以您不需要记住您的cell数组第7列中有哪些信息。此外,您可以轻松地在结构体中包含一个“help”字段,可以在其中放置一些额外的字段解释,如果有必要的话。

结构体也对数据存储非常有用,因为如果您想在以后更新您的代码,可以将其替换为对象而无需更改您的代码(至少在您预先分配结构体的情况下)。它们具有相同的语法,但对象将允许您添加更多功能,例如依赖属性(即基于其他属性动态计算的属性)。

最后,请注意,单元格和结构体会为每个字段添加几个字节的开销。因此,如果您想使用它们处理大量数据,最好使用包含数组的结构体/单元格,而不是具有仅包含标量的结构体/单元格的大型数组。


6

这段代码表明,在赋值和检索时,单元数组的速度大约是结构体的两倍。我没有分离这两个操作。可以很容易地修改代码来实现。

运行"whos"之后,它们使用非常相似的内存量。

我的目标是用Python术语创建一个“列表的列表”,也许是“数组的数组”。

我希望这对您有趣/有用!

%%%%%%%%%%%%%%  StructVsCell.m %%%%%%%%%%%%%%%

clear all

M = 100; % number of repetitions
N = 2^10; % size of cell array and struct


for m = 1:M
    % Fill up a template cell array with
    % lists of randomly sized matrices with
    % random elements.
    template{N} = 0;
    for n = 1:N
        r1 = round(24*rand());
        r2 = round(24*rand());
        r3 = rand(round(r2*rand),round(r1*rand()));
        template{N} = r3;
    end

    % Make a cell array equivalent
    % to the template.
    cell_array = template;

    % Create a struct with the
    % same data.
    structure = struct('data',0);
    for n = 1:N
        structure(n).data = template{n};
    end

    % Time cell array
    tic;
    for n = 1:N
        data = cell_array{n};
        cell_array{n} = data';
    end
    cell_time(m) = toc;

    % Time struct
    tic;
    for n = 1:N
        data = structure(n).data;
        structure(n).data = data';
    end
    struct_time(m) = toc;
end

str = sprintf('cell array: %0.4f',mean(cell_time));
disp(str);
str = sprintf('struct: %0.4f',mean(struct_time));
disp(str);
str = sprintf('struct_time / cell_time: %0.4f',mean(struct_time)/mean(cell_time));
disp(str);

% Check memory use
whos

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

哦,还要感谢@jonas告诉我CELLFUN。我之前不知道这个函数,现在会在我正在编写的代码中使用它。 - abalter
根据你的代码,struct 在我的情况下快了四倍。 - embert

3
首先,我赞同yuk的回答。在长期来看,清晰度通常更为重要。
然而,根据数据的不规则形状,您可能还有两个选项:
选项3:structScalar.structField(fieldIndex) 选项4:structScalar.structField{cellIndex} 在这四个选项中,#3对于大量元素具有最小的内存开销(它最小化了总矩阵数量),而当大量元素指的是>100,000时。如果您的代码适合在structField上进行向量化,则可能是性能优势。如果无法将structField的每个元素收集到单个矩阵中,则选项4具有符号优点,但没有选项3的内存和性能优势。这两个选项都可以更轻松地在整个数据集上使用arrayfun或cellfun,但代价是需要单独添加或删除每个字段的元素。选择取决于您如何使用数据,这让我们回到yuk的答案-选择使代码最清晰的选项。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接