1

MATLAB tables let you index into any column/field using the row name, e.g., MyTable.FourthColumn('SecondRowName'). Compared to this, dictionaries (containers.Map) seem primitive, e.g., it serves the role of a 1-column table. It also has its own dedicated syntax, which slows down the thinking about how to code.

I'm beginning to think that I can forget the use of dictionaries. Are there typical situations for which that would not be advisable?

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
user2153235
  • 388
  • 1
  • 11
  • In the mean time, here are related questions: https://stackoverflow.com/q/34767016/7328782 , https://stackoverflow.com/q/49826177/7328782 – Cris Luengo Dec 30 '18 at 15:12
  • Thanks for the links, Cris. I am indeed referring to Containers.Map. The comparison with struct is indeed relevant, although they refer to using the struct field name as the key whereas I am referring to the table row name as the key. Admittedly, I can also use the table field name as the key, but they are subject to more restrictions. *If* I confine the scope of the question to cases in which the key consists only of string, then in comparison with Containers.Map, it seems that a table offers much more flexibility in all other respects. – user2153235 Dec 31 '18 at 02:35

2 Answers2

3

TL;DR: No. containers.Map has uses that cannot be replaced with a table. And I would not choose a table for a dictionary.


containers.Map and table have many differences worth noting. They each have their use. A third container we can use to create a dictionary is a struct.

To use a table as a dictionary, you'd define only one column, and specify row names:

T = table(data,'VariableNames',{'value'},'RowNames',names);

Here are some notable differences between these containers when used as a dictionary:

  • Speed: The struct has the fastest access by far (10x). containers.Map is about twice as fast as a table when used in an equivalent way (i.e. a single-column table with row names).

  • Keys: A struct is limited to keys that are valid variable names, the other two can use any string as a key. The containers.Map keys can be scalar numbers as well (floating-point or integer).

  • Data: They all can contain heterogeneous data (each value has a different type), but a table changes how you index if you do this (T.value(name) for homogeneous data, T.value{name} for heterogeneous data).

  • Syntax: To lookup the key, containers.Map provides the most straight-forward syntax: M(name). A table turned into a dictionary requires the pointless use of the column name: T.value(name). A struct, if the key is given by the contents of a variable, looks a little awkward: S.(name).

  • Construction: (See the code below.) containers.Map has the most straight-forward method for building a dictionary from given data. The struct is not meant for this purpose, and therefore it gets complicated.

  • Memory: This is hard to compare, as containers.Map is implemented in Java and therefore whos reports only 8 bytes (i.e. a pointer). A table can be more memory efficient than a struct, if the data is homogeneous (all values have the same type) and scalar, as in this case all values for one column are stored in a single array.

  • Other differences:

    • A table obviously can contain multiple columns, and has lots of interesting methods to manipulate data.

    • A stuct is actually a struct array, and can be indexed as S(i,j).(name). Of course name can be fixed, rather than a variable, leading to S(i,j).name. Of the three, this is the only built-in type, which is the reason it is so much more efficient.

Here is some code that shows the difference between these three containers for constructing a dictionary and looking up a value:

% Create names
names = cell(1,100);
for ii=1:numel(names)
   names{ii} = char(randi(+'az',1,20));
end
name = names{1};

% Create data
values = rand(1,numel(names));

% Construct
M = containers.Map(names,values);

T = table(values.','VariableNames',{'value'},'RowNames',names);

S = num2cell(values);
S = [names;S];
S = struct(S{:});

% Lookup    
M(name)
T.value(name)
S.(name)

% Timing lookup
timeit(@()M(name))
timeit(@()T.value(name))
timeit(@()S.(name))

Timing results (microseconds):

M: 16.672
T: 23.393
S:  2.609
Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • All true. In some cases, the readability advantage of setting up a lookup table of literals favours tables, if that is important to the context: `Literals = { 'RowName' 'NumDat'; 'dog' 9 ; 'cat' 12 ; 'mouse' pi ; 'horse' exp(1) ; }; T = cell2table( Literals(2:end,:), 'VariableNames',Literals(1,:) ); T.Properties.RowNames = T.RowName`. I would have each statement and cell row in a separate line so that the tabular nature and key/value associations are instantly seen. – user2153235 Dec 31 '18 at 14:49
  • Along the lines of your point about interesting ways to manipulate table data, you can look up a series of keys at once, e.g., `T.NumDat({'mouse' 'dog'})`. If you have multiple string columns, you can also swap them in as RowNames for use as keys. – user2153235 Dec 31 '18 at 15:08
  • 1
    @user2153235: With `Literals` you can also easily build a struct and a `Map`: `struct(Literals{:})` (actually needs a transpose first), and `containers.Map(Literals(1,:),Literals(2,:))`. In both cases the first row of `Literals` is not needed. – Cris Luengo Dec 31 '18 at 15:20
  • @user2153235: If this type of manipulation is needed, then indeed, use a `table`. – Cris Luengo Dec 31 '18 at 15:21
  • That conversion of cell array to struct is cool. Something to keep in mind if I need the speed advantage, and I'm doing scalar lookups of a single value. Thanks. – user2153235 Dec 31 '18 at 16:23
0

You can go simpler, you can access structs using string field:

clear
% define
mydata.('vec')=[2 4 1]; 
mydata.num=12.58;
% get 
select1='num'; 
value1=mydata.(select1); %method 1 
select2='vec'; 
value2=getfield(mydata,select2) %method 2 
Mendi Barel
  • 3,350
  • 1
  • 23
  • 24
  • True that! Do you have a code pattern that builds up the lookup table in one statement, e.g., like [`cell2table`](http://www.mathworks.com/help/matlab/ref/cell2table.html?searchHighlight=cell2table&s_tid=doc_srchtitle#btzdqfx-3)? I'm thinking about how to keep code streamlined. As well, what motivated me to post the question was wondering whether there was anything that dictionaries have to offer which might cause one not to dispense with them entirely. Thanks. – user2153235 Dec 30 '18 at 14:38
  • @user2153235 You can use `cell2struct`... These are all different constructs with their own uses though. – Wolfie Dec 31 '18 at 08:46
  • I should have clarified that the link points to how converting from cells as the initializing data allows for the input data to be very well laid out so that the associations are immediately obvious. I provide an example in my comment to Cris Luengo's answer, along with mention of advantages in vectorized table lookups and convenient swapping of keys. I must be in a phase of puppy love with tables. – user2153235 Dec 31 '18 at 15:14