92

Does MATLAB have any support for hash tables?


Some background

I am working on a problem in Matlab that requires a scale-space representation of an image. To do this I create a 2-D Gaussian filter with variance sigma*s^k for k in some range., and then I use each one in turn to filter the image. Now, I want some sort of mapping from k to the filtered image.

If k were always an integer, I'd simply create a 3D array such that:

arr[k] = <image filtered with k-th guassian>

However, k is not necessarily an integer, so I can't do this. What I thought of doing was keeping an array of ks such that:

arr[find(array_of_ks_ = k)] = <image filtered with k-th guassian>

Which seems pretty good at first thought, except I will be doing this lookup potentially a few thousand times with about 20 or 30 values of k, and I fear that this will hurt performance.

I wonder if I wouldn't be better served doing this with a hash table of some sort so that I would have a lookup time that is O(1) instead of O(n).


Now, I know that I shouldn't optimize prematurely, and I may not have this problem at all, but remember, this is just the background, and there may be cases where this is really the best solution, regardless of whether it is the best solution for my problem.

Matthew Simoneau
  • 6,199
  • 6
  • 35
  • 46
Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319

6 Answers6

121

Consider using MATLAB's map class: containers.Map. Here is a brief overview:

  • Creation:

    >> keys = {'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', ...
      'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', 'Annual'};
    
    >> values = {327.2, 368.2, 197.6, 178.4, 100.0,  69.9, ...
      32.3,  37.3,  19.0,  37.0,  73.2, 110.9, 1551.0};
    
    >> rainfallMap = containers.Map(keys, values)
    
    rainfallMap = 
      containers.Map handle
      Package: containers
    
      Properties:
            Count: 13
          KeyType: 'char'
        ValueType: 'double'
      Methods, Events, Superclasses
    
  • Lookup:

    x = rainfallMap('Jan');
    
  • Assign:

    rainfallMap('Jan') = 0;
    
  • Add:

    rainfallMap('Total') = 999;
    
  • Remove:

    rainfallMap.remove('Total')
    
  • Inspect:

    values = rainfallMap.values;
    keys = rainfallMap.keys;
    sz = rainfallMap.size;
    
  • Check key:

    if rainfallMap.isKey('Today')
        ...
    end
    
Amro
  • 123,847
  • 25
  • 243
  • 454
  • 7
    Wow, I didn't know that! +1. Do you know whether they're much faster than logical indexing? – Jonas Aug 28 '10 at 19:11
  • 3
    Containers.Map was added in MATLAB 7.7 (R2008b) see http://www.mathworks.com/access/helpdesk/help/techdoc/rn/brqyzax-1.html . New in R2010a is a constructor to specify key type as well as value type. M = containers.Map('KeyType', kType, 'ValueType', vType) – zellus Aug 28 '10 at 19:20
  • @Jonas: I haven't used them extensively, it would be interesting to see how they compare against using logical indexing for lookup.. – Amro Aug 28 '10 at 19:24
  • @zellus: my bad, I guess I only noticed them recently :) – Amro Aug 28 '10 at 19:25
  • 9
    @zellus,@amro: Isn't it annoying how there is no history of the commands in Matlab? – Jonas Aug 28 '10 at 19:33
  • @Jonas: Good point, a command history might be interesting. Overall the documentation is outstanding, compared with other products. I was waiting for the new constructor, therefore I knew that the maps where available before R2010a. – zellus Aug 28 '10 at 20:55
  • 4
    Lookup: rainfallMap('Jan'); Assign: rainfallMap('Jan') = 'zero'; Inspect: rainfallMap.values; rainfallMap.keys; rainfallMap.size; Check key: rainfallMap.isKey('Today'); – Evgeni Sergeev Oct 05 '12 at 07:00
26

Matlab R2008b (7.7)’s new containers.Map class is a scaled-down Matlab version of the java.util.Map interface. It has the added benefit of seamless integration with all Matlab types (Java Maps cannot handle Matlab structs for example) as well as the ability since Matlab 7.10 (R2010a) to specify data types.

Serious Matlab implementations requiring key-value maps/dictionaries should still use Java’s Map classes (java.util.EnumMap, HashMap, TreeMap, LinkedHashMap or Hashtable) to gain access to their larger functionality if not performance. Matlab versions earlier than R2008b have no real alternative in any case and must use the Java classes.

A potential limitation of using Java Collections is their inability to contain non-primitive Matlab types such as structs. To overcome this, either down-convert the types (e.g., using struct2cell or programmatically), or create a separate Java object that will hold your information and store this object in the Java Collection.

You may also be interested to examine a pure-Matlab object-oriented (class-based) Hashtable implementation, which is available on the File Exchange.

Community
  • 1
  • 1
Yair Altman
  • 5,704
  • 31
  • 34
  • 1
    Another Matlab class-based implementation posted today: http://www.mathworks.com/matlabcentral/fileexchange/28586 – Yair Altman Aug 30 '10 at 19:18
19

You could use java for it.

In matlab:

dict = java.util.Hashtable;
dict.put('a', 1);
dict.put('b', 2);
dict.put('c', 3);
dict.get('b')

But you would have to do some profiling to see if it gives you a speed gain I guess...

tauran
  • 7,986
  • 6
  • 41
  • 48
14

Matlab does not have support for hashtables. EDIT Until r2010a, that is; see @Amro's answer.

To speed up your look-ups, you can drop the find, and use LOGICAL INDEXING.

arr{array_of_ks==k} = <image filtered with k-th Gaussian>

or

arr(:,:,array_of_ks==k) = <image filtered with k-th Gaussian>

However, in all my experience with Matlab, I've never had a lookup be a bottleneck.


To speed up your specific problem, I suggest to either use incremental filtering

arr{i} = GaussFilter(arr{i-1},sigma*s^(array_of_ks(i)) - sigma*s^(array_of_ks(i-1)))

assuming array_of_ks is sorted in ascending order, and GaussFilter calculates the filter mask size based on the variance (and uses, 2 1D filters, of course), or you can filter in Fourier Space, which is especially useful for large images and if the variances are spaced evenly (which they most likely aren't unfortunately).

Community
  • 1
  • 1
Jonas
  • 74,690
  • 10
  • 137
  • 177
12

It's a little clugey, but I'm surprised nobody has suggested using structs. You can access any struct field by variable name as struct.(var) where var can be any variable and will resolve appropriately.

dict.a = 1;
dict.b = 2;

var = 'a';

display( dict.(var) ); % prints 1
Mark Elliot
  • 75,278
  • 22
  • 140
  • 160
  • 1
    It would break if you use a number as a fieldname: `dict.('2')`: http://www.mathworks.com/access/helpdesk/help/techdoc/matlab_prog/br04bw6-38.html#br1v5bu-1 – Amro Aug 28 '10 at 19:35
  • Also, the variables have to be integers: `dict.(['k',num2str(1)])` works, but `dict.(['k',num2str(1.1)])` fails, and if the values are integers, you can use them to index directly. It's a nice idea otherwise. – Jonas Aug 28 '10 at 19:50
  • @Amro, @Jonas, fair points, if the the keys were integers you wouldn't need to use this trick (an array would make more sense)...if the keys are arbitrary floats this is a little more challenging, but I'd prefix with a letter and replace the `.` with an `_`. – Mark Elliot Aug 28 '10 at 22:14
  • 6
    The above issues with using structures can be avoided by variabilizing the strings before adding as field names: `dict.(genvarname(['k',num2str(1.1)]))` – foglerit Jan 29 '12 at 17:03
1

You can also take advantage of the new type "Table". You can store different types of data and get statistics out of it really easy. See http://www.mathworks.com/help/matlab/tables.html for more info.

Lei Zhang
  • 500
  • 4
  • 15