Reputation: 257
I would like to know if there exists a way in MATLAB to create a dictionary like in Python.
I have several Port Name and Port Type and I would like to create a dictionary like this :
dict = {PortName : PortType, PortName : PortType, ...}
Upvotes: 3
Views: 8097
Reputation: 112749
EDIT: Since R2022b Matlab has a dictionary
type, which is recommended over containers.Map
.
The closest analogy is containers.Map
:
containers.Map
: Object that maps values to unique keys
The keys are character vectors, strings, or numbers. The values can have arbitrary types.
To create the map you pass containers.Map
a cell array of keys and a cell array of values (there are other, optional input arguments):
>> dict = containers.Map({ 'a' 'bb' 'ccc' }, { [1 2 3 4], 'Hey', {2 3; 4 5} });
>> dict('a')
ans =
1 2 3 4
>> dict('bb')
ans =
'Hey'
>> dict('ccc')
ans =
2×2 cell array
{[2]} {[3]}
{[4]} {[5]}
You can also append key-value pairs to an existing map:
>> dict('dddd') = eye(3);
>> dict('dddd')
ans =
1 0 0
0 1 0
0 0 1
However, depending on what you want to do there are probably more Matlab-like ways to do it. Maps are not so widely used in Matlab as dictionaries are in Python.
Upvotes: 8
Reputation: 4557
MATLAB R2022b has a new dictionary
datatype that is significantly better than containers.Map
. A tutorial describing it can be found on The MATLAB blog https://blogs.mathworks.com/matlab/2022/09/15/an-introduction-to-dictionaries-associative-arrays-in-matlab/
For example:
names = ["Mike","Dave","Bob"];
weights = [89,75,68]; % weight in kilograms
gym = dictionary(names,weights) % Vectorised constructor. Performs elementwise mapping.
gives
gym =
dictionary (string ⟼ double) with 3 entries:
"Mike" ⟼ 89
"Dave" ⟼ 75
"Bob" ⟼ 68
Upvotes: 6
Reputation: 19806
I wrote a func to make containers.Map
via dict(a=1, b='yes')
syntax. Dunno if foulproof but seems to work, also wrote a function to pretty print a containers.Map
. Demo:
d = dict(a=1, mode='fast', arr=[[1 2 3]; [5 6 7]], yes=dict(k=2));
disp(dict2str(d))
a=1, arr=[1 2 3] [5 6 7], mode='fast', yes=dict(k=2,),
also guards against very long prints but this can be improved:
d = dict(a=randn(1000));
disp(dict2str(d))
a=<double>,
function out = dict(varargin)
% DICT Python dictionary syntax
%
% out = dict(a=1, mode='fast', arr=[1 2 3], yes=dict(k=2))
%
% Show with
%
% disp(dict2str(out))
out = containers.Map('UniformValues', false);
current_key = '';
for i=1:length(varargin)
if mod(i, 2)
current_key = varargin{i};
else
out(current_key) = varargin{i};
end
end
end
function out = dict2str(d, C)
% DICT2STR
%
% `disp(out)` is like
% analytic=true, normalize='l1', paths_exclude=None, r_psi=.70711
arguments
d;
C.delim = ', ';
C.max_value_length = 50;
end
keys = d.keys;
values = d.values;
out = "";
for i=1:length(keys)
k = keys{i};
v = values{i};
if class(v) == "containers.Map"
vs = "dict(" + dict2str(v) + ")";
elseif isnumeric(v) && length(v) > 1
vs = "[" + join(string(v)) + "]";
elseif isempty(v)
vs = "None";
elseif ismember(class(v), ["string", "char"])
vs = sprintf("'%s'", join(string(v)));
else
vs = join(string(v));
end
if C.max_value_length && length(vs) > C.max_value_length
vs = "<" + class(v) + ">";
end
out = out + sprintf("%s=%s%s", join(string(k)), join(string(vs)), C.delim);
end
% strip delimiter
for i=1:length(C.delim)
out = strip(out, 'right', C.delim(i));
end
end
Upvotes: 0
Reputation: 60695
You can use containers.Map
as suggested by Luis Mendo in the other answer, but I think in this case a struct
is much simpler:
>> dict = struct('a',[1 2 3 4], 'bb','Hey', 'ccc',{2 3; 4 5});
>> dict.('a')
ans =
1 2 3 4
>> dict.a
ans =
1 2 3 4
>> dict.b
ans =
'Hey'
>> dict.ccc
ans =
2×2 cell array
{[2]} {[3]}
{[4]} {[5]}
>> dict.dddd = eye(3);
>> dict.('eee') = eye(3);
>> dict.dddd
ans =
1 0 0
0 1 0
0 0 1
That is, the struct is always indexed using .('name')
or simply .name
. But there are restrictions on what 'name' can be (it must be a valid variable name), unlike for the Map
.
See this other answer to learn about important differences between the two approaches.
Upvotes: 5