12

I would like to understand the difference between container map and a struct in matlab.

From what I've looked, it seems that the advantages of a container map is that it can use any number or string as a key, while a struct field can only take strings that are legit variable names (e.g. it won't accept mystruct.('123string'))

Are there any other advantages for using a container map over a struct?

Thanks

Yuval Atzmon
  • 5,645
  • 3
  • 41
  • 74
  • In my eyes structs and containers are completely different things. Containers can store key-value pairs and structs can story anyhing. Please be more specific, what your question is. In general containers are rarely used in Matlab, as their implementation is a little inconvenient. Please post an example, where you could use both. – Robert Seifert Jan 13 '16 at 12:56
  • 3
    From my point of view, they both are different names for a dictionary. You could do both `mystruct.('field') = value;` or `mymap('field') = value`, where `value` is not restricted to a type. – Yuval Atzmon Jan 13 '16 at 14:42
  • You could, yes. But in case of a container `value` could be a **single** value of type *`'char', 'logical', 'double', 'single', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', or 'uint64'.`*, while in case of structs it could be also a matrix, a cell array, another struct even the instance of another class or a function handle. So your intended use of a struct is the most simple one. I'd also say somehting like `mystruct.('field')` is more like an additional feature to allow dictionary-like accessing of variables. The more common one would be just `mystruct.field`. – Robert Seifert Jan 13 '16 at 15:03
  • 2
    Sorry, but that is wrong. You can assign any value to a container map. – Yuval Atzmon Jan 13 '16 at 15:16
  • After trying something like `mapObj = containers.Map( {'key1', 'key2', 'key3', 'key4'}, [{{[1,2,3],[4,5,6]}}, {@(x) x^2}, 197.6, 178.4])`, I agree, but there remains a *but*: you need to wrap every value into a cell. This is undocumented behaviour, and I'd guess no intended use, as this is what structs are for ;) – Robert Seifert Jan 13 '16 at 15:31
  • 1
    You don't have to wrap the values into a cell. – Yuval Atzmon Jan 13 '16 at 15:47
  • `mapObj = containers.Map( {'key1', 'key2', 'key3', 'key4'}, [{[1,2,3],[4,5,6]}, @(x) x^2, 197.6, 178.4])` is not working with R2015a. – Robert Seifert Jan 13 '16 at 16:17
  • Just try: `theMap = containers.Map(); theMap('abc') = [2 2 2]` – Yuval Atzmon Jan 13 '16 at 16:32

3 Answers3

12

The concepts behind a container map and a struct are quite different:

A container map is used to create a mapping or indexing. For example if you have a matrix A and want to index the element in the second row and second column, you will index it using A(2,2). For numbers, matrices and so on, where you want to index a specific row number, this is convenient. Assume however, you have a situation as shown in the following example by Mathworks:

example

Here you have an array of values, which you could index as value(1) for January, and so on. However this is not very legible. It would be much more convenient if you could index it with value('Jan'). This is exactly what container maps offer. As @marsei remarked in his comment, container maps are a Java-based, unordered, construct, that uses hash-tables for indexing.

A struct is a different construct, which is C-based and ordered (thanks for the insignt @marsei). The main use of struct is to help you store data in a more logical way. For example when using images, you often have two variables: one for the image data, and one for the color map. Without structs, you need to keep those two separate variables in the workspace. For multiple images this gets very confusing (e.g. using names like img0_data, img0_map and so on). A struct helps you organize this in a simple way: A struct called img0 with the fields data and map.

In the context of dictionaries, both constructs are more or less equivalent, though structs usually seem to be faster than container maps. Plus, as already mentioned in the question, the key of a container map can be any single value, while for structs it has to be a string.

hbaderts
  • 14,136
  • 4
  • 41
  • 48
  • 3
    I'd be glad get some feedback from the down-voter, so I can improve the answer. – hbaderts Jan 13 '16 at 14:07
  • So what you basically say is that the difference is more semantic/conceptual ? Because from my point of view, they both are different names for a dictionary. You could do both `mystruct.('field') = value;` or `mymap('field') = value`, where `value` is not restricted to a type. (BTW: I am not the down-voter). – Yuval Atzmon Jan 13 '16 at 14:44
  • 2
    Yes, the map is definitely a dictionary, a mapping x --> y without any restrictions on x and y. A struct is a data structure, a way to save data in a logical way. E.g. you can create an array of structs (e.g. `person(1).age`), but you can't create an array of maps (afaik). This is similar to e.g. C/C++ structs: you define how data is saved, and then instance objects of this struct to save data. – hbaderts Jan 13 '16 at 14:52
  • 4
    A Matlab structure is an ordered list of name-value pairs and is C-based. A map container is Java-based and is basically the same thing (but unordered). Both use a hash table to access their values, and both can use a "fieldname" to access the data: `s.field1` and `cm('key1')`. Structures are faster to work with. (*I didn't down vote*). – marsei Jan 13 '16 at 14:59
  • But you cannot use map for e.g. an *1*-by-*N* array of persons, each with a field `'name'` and `'age'`, or am I mistaken here? Exactly such constructs are (afaik) the main use of struct in MATLAB. – hbaderts Jan 13 '16 at 15:05
  • Sure. Structures are more capable of handling different objects. But the context of the question here is about dictionary, i.e. pairing a key to a single value. – marsei Jan 13 '16 at 15:15
  • Ok, if the dictionary tag means that the question is only in the context of 1:1 dictionaries, then of course. I interpreted the question in a general way: when to use which construct. – hbaderts Jan 13 '16 at 15:18
  • (OP here) My question was meant to be general. – Yuval Atzmon Jan 13 '16 at 15:20
  • @hbaderts, you can assign two fields for each key. See http://stackoverflow.com/questions/10758285/matlab-map-initialisation-from-a-structure-array – Yuval Atzmon Jan 13 '16 at 15:22
  • @hbaderts, can you update your answer to contain the info about arrays of struct and the java vs C and ordered-vs-unordered (by @marsei)? – Yuval Atzmon Jan 13 '16 at 15:24
  • This answer doesn’t hit any of the relevant differences between a `struct` and a `Map`. See [this other answer](https://stackoverflow.com/a/38933556/7328782) for that. – Cris Luengo Nov 26 '18 at 14:45
10

Functionality wise, the containers.Map is almost a generalization of struct, i.e.:

  • Keys of containers.Map are not limited to be valid identifiers strings.
  • Optionally, type checking on containers.Map values can be enforced.

One notable difference is that instances of containers.Map are passed by reference, whereas struct objects are passed by value.

Design wise, containers.Map were introduced to fill the gap with java.util.Map (see Using Java Collections in Matlab). This somehow explains the different pass-by convention, because all instances of Java Object are passed by reference in Matlab (see Pass Data to Java Methods).

History wise, containers.Map came in R2008b, i.e. after struct, which came before R2006a.

Stefano Soffia
  • 101
  • 1
  • 4
  • 2
    “struct, which came before R2006a.” That’s wha the docs say, because the docs have been keeping track of new functionality since 2006. Structs has been around for a while when I started using MATLAB in 1998 or so. But the dynamic indexing didn’t come around until later (I don’t remember exactly when, it was probably with version 7.0). – Cris Luengo Nov 26 '18 at 14:35
  • 1
    Another difference is that, if you were to make an array of `Map`, each could have different keys, but an array of struct has uniform keys. (By the way, this is an excellent answer.) – Cris Luengo Nov 26 '18 at 14:42
4

After reading @hbaderts's answer, it got me wondering what the speed difference actually is. Hence, I went ahead and tried some benchmark test.

%%  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));

Result:.

hashmap read time.

avg: 0.301 seconds.

max: 0.320 seconds.

hashmap write time.

avg: 0.233 seconds.

max: 0.247 seconds.

hashmap matrix read time.

avg: 0.305 seconds.

max: 0.323 seconds.

hashmap matrix write time.

avg: 0.011 seconds.

max: 0.016 seconds.

struct read time.

avg: 0.059 seconds.

max: 0.066 seconds.

struct write time.

avg: 0.040 seconds.

max: 0.046 seconds.

Let me know if this test looks valid!

jjc1215
  • 41
  • 2