Matlab中容器Map和结构体的区别

12
我想了解 MATLAB 中容器映射和结构体之间的区别。根据我的了解,容器映射的优点是可以使用任何数字或字符串作为键,而结构体字段只能使用合法的变量名字符串作为键(例如,它不会接受mystruct.('123string'))。除此之外,还有哪些使用容器映射比结构体更好的优点吗?谢谢。

在我看来,结构体和容器是完全不同的东西。容器可以存储键值对,而结构体可以存储任何东西。请更具体地说明您的问题。通常情况下,在Matlab中很少使用容器,因为它们的实现有点不方便。请提供一个示例,您可以在其中同时使用两者。 - Robert Seifert
3
在我看来,它们都是字典的不同名称。你可以使用 mystruct.('field') = value; 或者 mymap('field') = value,其中的 value 不受类型限制。 - Yuval Atzmon
2
抱歉,但那是错误的。你可以给容器映射分配任何值。 - Yuval Atzmon
尝试类似mapObj = containers.Map({'key1', 'key2', 'key3', 'key4'}, [{{[1,2,3],[4,5,6]}}, {@(x) x^2}, 197.6, 178.4}])后,我同意,但仍有一种情况:您需要将每个值包装成单元格。这是未记录的行为,我猜测没有预期的用途,因为这就是结构体的作用;) - Robert Seifert
1
您不必将值包装到单元格中。 - Yuval Atzmon
显示剩余3条评论
3个回答

12

容器映射和结构体背后的概念是非常不同的:

容器映射用于创建映射或索引。例如,如果您有一个矩阵 A 并想要索引第二行和第二列中的元素,则将使用 A(2,2) 进行索引。对于数字、矩阵等需要索引特定行号的情况,这是很方便的。但是,假设您有一种情况如下面的示例所示,并由 Mathworks 给出:

example

这里有一组值的数组,您可以像 value(1) 那样对其进行索引以获取一月的值,以此类推。但是这不太易读。如果您能使用 value('Jan') 进行索引将更加方便。这正是容器映射所提供的。正如 @marsei 在他的评论中指出的那样,容器映射是一种基于 Java 的无序结构,它使用哈希表进行索引。

结构体是一个不同的结构,它基于 C 并且是有序的 (感谢 @marsei 给出的洞见)。结构体的主要用途是帮助您以更加逻辑的方式存储数据。例如,在使用图像时,您通常有两个变量: 一个用于图像数据,另一个用于调色板。没有结构体,您需要在工作空间中保持这两个单独的变量。对于多个图像,这会变得非常混乱 (如使用诸如 img0_dataimg0_map 等名称)。结构体可以帮助您以简单的方式组织这些内容: 一个名为 img0 的结构体,具有字段 datamap

在字典的上下文中,两种结构在某种程度上是相等的,虽然结构体通常似乎比容器映射更快。此外,如问题中所提到的,容器映射的key可以是任何单个值,而对于结构体,它必须是一个字符串。


3
我很乐意得到下投票者的反馈,这样我就可以改进答案。请您提供建议。 - hbaderts
2
是的,map(映射)绝对是一个字典,它将x映射到y,没有任何对x和y的限制。而struct(结构体)则是一种数据结构,一种以逻辑方式保存数据的方法。例如,您可以创建一个结构体数组(例如person(1).age),但您不能创建一个映射数组(据我所知)。这类似于C/C++中的结构体:您定义如何保存数据,然后实例化此结构体的对象来保存数据。 - hbaderts
4
Matlab结构体是一个由名称-值对有序列表组成的、以C为基础的数据类型。Map容器则是基于Java实现的,本质上也是同样的东西(但是无序)。两者均使用哈希表来访问其值,并且都可以使用“字段名”来访问数据:s.field1cm('key1')。结构体的处理速度更快。(我没有给它点踩 - marsei
但是你不能使用map来处理例如一个由人组成的N1列数组,每个人都有一个名字和年龄字段,我错了吗?在MATLAB中,这样的结构体构造是(据我所知)struct的主要用途。 - hbaderts
@hbaderts,你可以为每个键分配两个字段。请参考 http://stackoverflow.com/questions/10758285/matlab-map-initialisation-from-a-structure-array - Yuval Atzmon
显示剩余6条评论

10
就功能而言,containers.Map 几乎是 struct 的泛化,即:
  • containers.Map 的键不限于有效的标识符字符串。
  • 可以选择强制执行对 containers.Map 值的类型检查。
一个值得注意的区别是,containers.Map 实例通过引用传递,而 struct 对象则通过值传递。
设计上,containers.Map 是为了填补与 java.util.Map 之间的差距而引入的(参见在 Matlab 中使用 Java 集合)。这在某种程度上解释了不同的传递约定,因为在 Matlab 中,所有 Java Object 的实例都是通过引用传递的(参见将数据传递给 Java 方法)。
历史上,containers.Map 是从 R2008b 开始引入的,在此之前是 struct,它是在 R2006a 之前引入的。

2
“struct,在R2006a之前就已经存在了。”这是文档中所说的,因为自2006年以来,文档一直在跟踪新功能。当我在1998年左右开始使用MATLAB时,结构体已经存在了一段时间。但是动态索引直到后来才出现(我不记得确切的时间,可能是在7.0版本中)。 - Cris Luengo
1
另一个区别是,如果你要创建一个 Map 数组,每个 Map 可以有不同的键,但结构体数组具有统一的键。(顺便说一下,这是一个很好的答案。) - Cris Luengo

4

在阅读了@hbaderts的答案后,我想知道实际的速度差异是多少。因此,我进行了一些基准测试。

%%  Below is to test read/write speed of struct, hashMap, and hashMap matrix assignment
numTrials= 10;
numKeys= 10000;
hw= zeros(1,numTrials);
hr= zeros(1,numTrials);
hmw= zeros(1,numTrials);
hmr= zeros(1,numTrials);
sw= zeros(1,numTrials);
sr= zeros(1,numTrials);
str= cell(1,numTrials);

for z= 1:numTrials

    for e=1:numKeys
        str{e}= strcat('adc',num2str(e)); 
    end

    % HashMap write
    tic;
    m= containers.Map(); 
    for a=1:numKeys
        m(str{a})=str{a}; 
    end 
    hw(z)= toc;

    % HashMap read
    tic;
    for b=1:numKeys
        m(str{b});
    end
    hr(z)= toc;

    % HashMap matrix write
    tic;
    keyval= cell(numKeys,1);
    for a=1:numKeys
        keyval{a}=str{a};
    end
    mm= containers.Map(keyval,keyval);
    hmw(z)= toc;

    % HashMap matrix read
    tic;
    for b=1:numKeys
        mm(str{b});
    end
    hmr(z)= toc;

    % Struct write
    tic;
    s= struct();
    for c=1:numKeys
        s.c.s.x.(str{c})= str{c}; 
    end 
    sw(z)= toc;

    % Struct read
    tic;
    for d=1:numKeys
        s.c.s.x.(str{d}); 
    end
    sr(z)= toc;

end

fprintf('hashmap read time\n avg: %.3f seconds\n max: %.3f seconds\n',sum(hr)/numTrials,max(hr));
fprintf('hashmap write time\n avg: %.3f seconds\n max: %.3f seconds\n',sum(hw)/numTrials,max(hw));
fprintf('hashmap matrix read time\n avg: %.3f seconds\n max: %.3f seconds\n',sum(hmr)/numTrials,max(hmr));
fprintf('hashmap matrix write time\n avg: %.3f seconds\n max: %.3f seconds\n',sum(hmw)/numTrials,max(hmw));
fprintf('struct read time\n avg: %.3f seconds\n max: %.3f seconds\n',sum(sr)/numTrials,max(sr));
fprintf('struct write time\n avg: %.3f seconds\n max: %.3f seconds\n',sum(sw)/numTrials,max(sw));

结果:

哈希表读取时间.

平均值:0.301秒。

最大值:0.320秒。

哈希表写入时间.

平均值:0.233秒。

最大值:0.247秒。

哈希表矩阵读取时间.

平均值:0.305秒。

最大值:0.323秒。

哈希表矩阵写入时间.

平均值:0.011秒。

最大值:0.016秒。

结构体读取时间.

平均值:0.059秒。

最大值:0.066秒。

请告诉我这个测试是否有效!


2
如果测试嵌入到函数中,您可能会得到不同的结果。JIT 的工作方式也会有所不同。 - Cris Luengo

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