MATLAB Answers

Dictionary / Map with array as key

36 views (last 30 days)
Verena Heußer
Verena Heußer on 23 Jun 2020
Edited: Verena Heußer on 2 Jul 2020
Hi there,
I'm looking for a way to initialize a map with an array as Key.
I am thinking of something like
map = containers.Map;
state = {1,2};
map(state) = 0;
However, the last line fails with
Error using containers.Map/subsasgn
Specified key type does not match the type expected for this container.
Is there any way I can initialize a Map with an array (not converted to char) as keys?
Or is there any other appropriate data structure for doing this?
Looking forward to your ideas;)

  2 Comments

Walter Roberson
Walter Roberson on 23 Jun 2020
The array is to be a single key, right?
Verena Heußer
Verena Heußer on 23 Jun 2020
Yes, I want the key to be an array.

Sign in to comment.

Answers (3)

Mehmed Saad
Mehmed Saad on 23 Jun 2020
Edited: Mehmed Saad on 27 Jun 2020
EDIT: First Answer is replaced
I donot understand why you dont want to go on characters. see the code below
M = containers.Map('KeyType','char','ValueType','double');
%% Single Key
key1 = [1.8 2.0 0.005];
valueSet = 327.2;
%% array key encoder
keySet = key_enc(key1);
M = containers.Map(keySet,valueSet);
%% array key decoder
key1_dbl = key_dec(M.keys);
assert(isequal(key1_dbl,key1));
where key_enc is double array to character converter. It basically converts double precision to hexadecimal (so that we dont lose any data due to rounding off)
Similarly key_dec is character to array double converter in order to retreive the key

For 2D Array

M = containers.Map('KeyType','char','ValueType','double');
%% More than 1
key1 = [1.8 2.0 0.005;4 5 6];
valueSet = [327.2 550];
%% array key encoder
keySet = key_enc(key1)
M = containers.Map(keySet,valueSet);
%% array key decoder
key1_dbl = key_dec(M.keys);
assert(isequal(key1_dbl,key1));
Point to remember
  1. a row is a complete key (i.e. a single row vector is considered as 1 key)
  2. key must be double precision (or any other 64 bit type)
  3. if you provide a 2D matrix, the number of rows represent number of keys
  4. key_inc can take both 1D and 2D input, it will return scalar output for 1D row vector. It's output type is cell array of character vectors
  5. key_dec take cell array of character vector as input and will return the double key in that format

Functions

Key Encoder
function key1_char = key_enc(key1)
[m,n] = size(key1);
key1_char=repmat({char(ones(1,16*n))},m,1);
tmp = num2hex(key1);
for ii=1:m
key1_char{ii,:} = reshape((tmp(ii:m:end,:).'),1,16*n);
end
end
Key Decoder
function key1_dbl = key_dec(key1_char)
m = numel(key1_char);
n = numel(key1_char{1});
key1_dbl = zeros(m,n/16);
for ii=1:m
key1_dbl(ii,:) = transpose(hex2num(transpose(reshape(key1_char{ii},16,n/16))));
end
end

Edit:

it is not necessary that assert works everytime because map gives sorted key out
For example
rng(2017)
key1 = randn(2,10);
valueSet =[1 2];
%% array key encoder
keySet = key_enc(key1)
keySet =
2×1 cell array
{'c00151bd6e3dafe9bfcefd29436d4...7b0bfe72b879a67bbee'}
{'3ff0c59e4de6586abff94c4bcb1ceb...ba03fd58526d0d66e84'}
Now see that they are not sorted in ascending order while
M = containers.Map(keySet,valueSet);
M.keys
ans =
1×2 cell array
{'3ff0c59e4de6586abff94c4bcb1ceb433fd72f384820035ebff29c1…'} {'c00151bd6e3dafe9bfcefd29436d4de93fe6733364db1b1fbfe17d1…'}
so if now you check them error will occur (assertion failed)

  5 Comments

Show 2 older comments
Verena Heußer
Verena Heußer on 26 Jun 2020
Hi:)
Thanks for the answer! This works fine for ints.
But is there also a way to insert a list of doubles as key?
Such as
key1 = [1.8 2.0 0.005]
Walter Roberson
Walter Roberson on 26 Jun 2020
No. Keys can be numeric scalars or character vectors or string() scalars, and cannot be cells and cannot be numeric vectors or non-scalar string objects.
Mehmed Saad
Mehmed Saad on 26 Jun 2020
see the updated answer for double array

Sign in to comment.


Walter Roberson
Walter Roberson on 26 Jun 2020
It isn't nice but ...
A container.Map can be a value. So you can create a top level container.Map that has a key that is 1.8, and the associated value is a second container.Map . The second container you would have a key that is 2.0 and associated value is a third container.Map . That third container.Map would have a key 0.005 and value would be whatever you were trying to associate as a value for key1 .
I would not expect this to be efficient. For efficiency, you would probably be better of doing something like an MD5 of key1 and use that as the key. Or see https://www.mathworks.com/matlabcentral/answers/534528-how-to-save-serialize-matlab-variables-to-a-byte-string#answer_439768 with the idea being that you would apply that to key1 and use the result as the key -- the advantage there would be that you would be able to look at the key list and deserialize the key list entries to find out what the resulting numeric keys were.

  0 Comments

Sign in to comment.


Verena Heußer
Verena Heußer on 2 Jul 2020
Edited: Verena Heußer on 2 Jul 2020
Dear all,
thanks for helping me out :)
I just wanted to share the solution I've come up with (don't know if it's the most efficient / elegant, but it totally serves my purposes).
So, I wanted to have arrays (1xn vectors) as keys, while the values are supposed to be real values.
I've decided to use the java.util.hashtable:
map = java.util.Hashtable;
state = [1, 2];
map.put(num2str(state), 0);
map.get(num2str(state))
>> ans =
0

  0 Comments

Sign in to comment.