34

I need to acces data by string index, like table('one') %returns 1. Is there such a data structure in MATLAB? How is it implemented?

NoobDev4iPhone
  • 5,531
  • 10
  • 33
  • 33

3 Answers3

55

In recent versions of MATLAB, there's the containers.Map data structure. See MATLAB Map containers for more. This removes some of the restrictions when using STRUCTs. For example

c = containers.Map
c('foo') = 1
c(' not a var name ') = 2
keys(c)
values(c)
Nigel Davies
  • 1,640
  • 1
  • 13
  • 26
Edric
  • 23,676
  • 2
  • 38
  • 40
17

A structure can be used as a sort of hash table:

>> foo.('one')=1

foo = 

    one: 1

>> foo.('two')=2;
>> x = 'two';
>> foo.(x)

ans =

     2

To query whether a structure contains a particular field (key), use isfield:

>> isfield(foo,'two')

ans =

     1

The disadvantage of this scheme is that only strings that are also valid Matlab variable names can be used as keys. For instance:

>> foo.('_bar')=99;
??? Invalid field name: '_bar'.

To get around this restriction, use one of the solutions in the question linked by Oli.

nibot
  • 14,428
  • 8
  • 54
  • 58
0

Just to add to the previous answers (could not comment on the other good answers) : a struct lookup like this:

s={};
s.abc = 1;   %insert a value in the struct, abc is your lookup hash
out = s.abc; % read it back

The actual read back of the value is about 10 times faster with a struct than using a container. Full test code as follows if interesting

function s=test_struct_lookup_hash_speed
%% test how a struct lookup speed works vs container, interesting

    s = {};  % hash table
    v = {};  % reverselookup table for testing

    nHashes = 1E4;  % vary this to see if read speed varies by size (NOT REALLY)
    nReads  = 1E6;

    fprintf('Generating hash struct of %i entries\n', nHashes);
    tic
    for i = 1:nHashes
        hashStr = md5fieldname(randi(1E8));
        s.(hashStr) = i;
        v{end+1} = hashStr;  %reverselookup
    end
    toc

    fprintf('Actual HashTable length (due to non unique hashes?): %i, and length of reverse table: %i\n',length(fieldnames(s)), length(v) );

    fprintf('Reading %i times from a random selection from the %i hashes\n', nReads, nHashes);
    vSubset = [ v(randi(nHashes,1,3))  ];

    for i = 1:length(vSubset)
       hashStr = vSubset{i};

       % measure read speed only
       tic
       for j = 1:nReads
         val = s.(hashStr);
       end
       toc

    end


    %% test CONTAINERS
    fprintf('Testing Containers\n');
    c = containers.Map;

    fprintf('Generating hash struct of %i entries\n', nHashes);
    tic
    for i = 1:nHashes
        hashStr = md5fieldname(randi(1E8));
        c(hashStr) = i;
        v{end+1} = hashStr;  %reverselookup
    end
    toc

   fprintf('Reading %i times from a random selection from the %i hashes\n', nReads, nHashes);
   vSubset = [ v(randi(nHashes,1,3))  ];

    for i = 1:length(vSubset)
       hashStr = vSubset{i};

       % measure read speed only
       tic
       for j = 1:nReads
         val = c(hashStr);
       end
       toc

    end    



    %% Get a valid fieldname (has to start with letter)   
    function h=md5fieldname(inp)
    h = ['m' hash(inp,'md5')];
    end


end
hh2000
  • 51
  • 5