getting list of values with list of keys for dictionary in Matlab - matlab

Suppose I use containers map to create a dictionary in MATLAB which has the following map:
1-A;
2-B;
3-C;
Denote the dictionary as D.
Now I have an input list [2,1,3], and what I am expecting is [B,A,C]. The problem is, I can't just use [2,1,3] as the input list for D, but only input 2,1 and 3 one by one for D and get B, A, C each time.
This can get the job done but as you can see, it's a bit less efficient.
So my question is: is there anything else I can do to let the dictionary return the whole list at the same time?

As far as I can find there is no one-step solution like python's dict.items. You can, however, get in a few lines. mydict.keys() gives you the keys of the dict as a cell array, and mydict.values() gives you the values as a cell array, so you can (in theory) combine those:
>> mykeys = mydict.keys();
>> myvals = mydict.values();
>> mypairs = [mykeys',myvals']
mypairs =
3×2 cell array
'A' [1]
'B' [2]
'C' [3]
However, in principle maps are unordered, and I can't find anything in the MATLAB documentation that says that the order returns by keys and the order returned by values is necessarily consistent (unlike Python). So if you want to be extra safe, you can call values with a cell array of the keys you want, which in this case would be all the keys:
>> mykeys = mydict.keys();
>> myvals = mydict.values(mykeys);
>> mypairs = [mykeys',myvals']
mypairs =
3×2 cell array
'A' [1]
'B' [2]
'C' [3]

Related

Specified key type does not match the type expected for this container matlab

I have a cell_array for which 29136x1 cell value shows in the workspace pallet. I also have a map new_labels with 4x1 Map in workspace pallet. Printing new_label on prompt gives
new_labels =
Map with properties:
Count: 4
KeyType: char
ValueType: double
Each entry in the cell_array is the key in the map, but the problem is there a type mismatch as keyType in map is char and entries of cell_array are of type cell.
Because of this I cannot access the map and hence something like the following:
arrayfun(#(x) new_labels(x), cell_array, 'un',0);
gives error Specified key type does not match the type expected for this container.
I tried converting to char type using char_cell_array = char(cell_array) but that converts the array to be of size 29136x4 which means every entry is just one char and not really a string.
Any help appreciated.
If you want to use the iterative way, you have to use cellfun. arrayfun operates on numeric arrays. Because cell_array is a cell array, you need to use cellfun instead of arrayfun as cellfun will iterate over cell arrays instead.
However, what you're really after is specifying more than one key into the dictionary to get the associated values. Don't use arrayfun/cellfun for that. There is a dedicated MATLAB function designed to take in multiple keys. Use the values method for that which is built-in to the containers.Map interface:
out = values(new_labels, cell_array);
By just using values(new_labels), this retrieves all of the values in the dictionary. If you want to retrieve specific values based on input keys, supply a second input parameter that is a cell array which contains all of the keys you want to access in the containers.Map object. Because you already have this cell array, you simply use this as the second input into values.
Running Example
>> A = containers.Map({1,2,3,4}, {'a','b','c','d'})
A =
Map with properties:
Count: 4
KeyType: double
ValueType: char
>> cell_array = {1,2,2,3,3,4,1,1,1,2,2};
>> out = values(A, cell_array)
out =
'a' 'b' 'b' 'c' 'c' 'd' 'a' 'a' 'a' 'b' 'b'

Function for comparing two cell arrays

I have a cell array (2000*10) with each cell containing a string such as '25:20:55'.
I want to write a function that accepts 10 inputs (say '25:02:33', '58:69:88', '25:54:96', '48:58:36', '58:54:88' and so on) and looks for a match in each column corresponding to input value for that particular column (i.e. the first input data corresponds to 1st column, 2nd to 2nd column of the stored data and so on.
How can I write a function for the above comparison?
Assuming the cell array contains strings, you can find matches using strcmp:
input = {'25:02:33', '58:69:88', '25:54:96', '48:58:36', '58:54:88'};
match_idx = strcmp(repmat(input, size(cell_data,1),1), cell_data);
If you only want to know if there are matches in the respective columns at all and do not care about the line index of the match, you can do
match = any(match_idx,1);
Use ismember
ismember(your_var, your_cell);
e.g.
c = {'a', 'b', 'c', 'd'};
ismember('b', c)
ans =
1
ismember('q', c)
ans =
0
In your case, something like could work
function arr = myfun(inputvec, inputmat)
for i=1:length(inputvec) %// where inputvec is the cell-vector with the strings you want to search for
arr(i) = ismember(inputvec{i}, inputmat{:,i});
end

output a structure from a input cell

I have a cell that has different data types (cell, logical, double, char) except structure. Now I have to write a function that will sort out different data types and output a structure with the field of those data types. The fields have to appear according to their appearance in the cell. So, if the first 'n' element(s) of the cell is double and the (n+1)th element is a char then the first field of the output structure will be double and second field will be char.
Below is an example where buildStructure is the function header. sa is the output structure.
ca = {'Moriarty', [true, false], false, {'Pink Suitcase'}}
sa = buildStructure(ca)
sa=>
char: {'Moriarty'}
logical: {[true, false] [false]}
cell: {{'Pink Suitcase'}}
I tried it writing a for loop to store different data types in different cells. However, then I am feeling so lost. How can I figure out which data type appeared when? To do that I stored all the classes in a huge string then used 'strfind' to find the place (thus time) of particular data type. But it is making things only complex. Any help will be appreciated! Thanks.
There are tests for all the data types. see: iscell, ischar, islogial and so on. Their results can be used to index the input.
you can complete this example code:
function out = magicfun(varargin)
il = cellfun(#islogical,varargin);
out = struct('logical',{varargin(il)});
You can use class(), isa(), and unique() to do it generically. It's like bdecaf's approach, but that'll require you to write a test for every type and use a variety of functions. Using class and isa will generalize to data of any type using a single test, and will be shorter to write.
Exact Types Only
By comparing class names from class(), you can partition the input in to types based on the exact (most specific) type of each input. The 'stable' option for unique() keeps the output fields in the order of the first occurrences of the types in the input. (In production code I would probably omit the 'stable' so the output ordering is canonicalized based on the type name, but it depends on your requirements.)
function out = break_types(in)
%BREAK_TYPES Partition a cell array based on the types of its contents
inTypes = cellfun(#class, in, 'UniformOutput',false);
[types,ax,bx] = unique(inTypes, 'stable');
out = struct;
for i = 1:numel(types)
ix = (bx == i);
out.(types{i}) = in(ix);
end
This is pretty complete and should work with anything that didn't do something silly like override class() or isa().
>> ca = {'Moriarty', [true, false], false, {'Pink Suitcase'}};
>> break_types(ca)
ans =
char: {'Moriarty'}
logical: {[1 0] [0]}
cell: {{1x1 cell}}
>>
Considering Inheritance
If you use isa(), you'll also pick up inheritance relationships for classes. For basic Matlab types, this will give you the same answer as the other implementation. But for classes that inherit from other types, it will categorize them in to all the types they match in the input and required lists.
function out = break_types(in)
%BREAK_TYPES Partition a cell array based on the types of its contents
inTypes = cellfun(#class, in, 'UniformOutput',false);
types = unique(inTypes, 'stable');
out = struct;
for i = 1:numel(types)
ix = cellfun(#(x) isa(x, types{i}), in);
out.(types{i}) = in(ix);
end
If you want to ensure that the output struct has an entry for some types even if there are no inputs of that type (so its field would contain an empty array), just append those type names to types before passing them to unique:
requiredTypes = { 'cell' 'int8', 'double', 'float' };
types = unique([inTypes requiredTypes], 'stable');

Iterating through struct fieldnames in MATLAB

My question is easily summarized as: "Why does the following not work?"
teststruct = struct('a',3,'b',5,'c',9)
fields = fieldnames(teststruct)
for i=1:numel(fields)
fields(i)
teststruct.(fields(i))
end
output:
ans = 'a'
??? Argument to dynamic structure reference must evaluate to a valid field name.
Especially since teststruct.('a') does work. And fields(i) prints out ans = 'a'.
I can't get my head around it.
You have to use curly braces ({}) to access fields, since the fieldnames function returns a cell array of strings:
for i = 1:numel(fields)
teststruct.(fields{i})
end
Using parentheses to access data in your cell array will just return another cell array, which is displayed differently from a character array:
>> fields(1) % Get the first cell of the cell array
ans =
'a' % This is how the 1-element cell array is displayed
>> fields{1} % Get the contents of the first cell of the cell array
ans =
a % This is how the single character is displayed
Since fields or fns are cell arrays, you have to index with curly brackets {} in order to access the contents of the cell, i.e. the string.
Note that instead of looping over a number, you can also loop over fields directly, making use of a neat Matlab features that lets you loop through any array. The iteration variable takes on the value of each column of the array.
teststruct = struct('a',3,'b',5,'c',9)
fields = fieldnames(teststruct)
for fn=fields'
fn
%# since fn is a 1-by-1 cell array, you still need to index into it, unfortunately
teststruct.(fn{1})
end
Your fns is a cellstr array. You need to index in to it with {} instead of () to get the single string out as char.
fns{i}
teststruct.(fns{i})
Indexing in to it with () returns a 1-long cellstr array, which isn't the same format as the char array that the ".(name)" dynamic field reference wants. The formatting, especially in the display output, can be confusing. To see the difference, try this.
name_as_char = 'a'
name_as_cellstr = {'a'}
You can use the for each toolbox from http://www.mathworks.com/matlabcentral/fileexchange/48729-for-each.
>> signal
signal =
sin: {{1x1x25 cell} {1x1x25 cell}}
cos: {{1x1x25 cell} {1x1x25 cell}}
>> each(fieldnames(signal))
ans =
CellIterator with properties:
NumberOfIterations: 2.0000e+000
Usage:
for bridge = each(fieldnames(signal))
signal.(bridge) = rand(10);
end
I like it very much. Credit of course go to Jeremy Hughes who developed the toolbox.

MATLAB "bug" (or really weird behavior) with structs and empty cell arrays

I have no idea what's going on here. I'm using R2006b. Any chance someone out there with a newer version could test to see if they get the same behavior, before I file a bug report?
code: (bug1.m)
function bug1
S = struct('nothing',{},'something',{});
add_something(S, 'boing'); % does what I expect
add_something(S.something,'test'); % weird behavior
end
function add_something(X,str)
disp('X=');
disp(X);
disp('str=');
disp(str);
end
output:
>> bug1
X=
str=
boing
X=
test
str=
??? Input argument "str" is undefined.
Error in ==> bug1>add_something at 11
disp(str);
Error in ==> bug1 at 4
add_something(S.something,'test');
It looks like the emptiness/nothingness of S.something allows it to shift the arguments for a function call. This seems like Very Bad Behavior. In the short term I want to find away around it (I'm trying to make a function that adds items to an initially empty cell array that's a member of a structure).
Edit:
Corollary question: so there's no way to construct a struct literal containing any empty cell arrays?
As you already discovered yourself, this isn't a bug but a "feature". In other words, it is the normal behavior of the STRUCT function. If you pass empty cell arrays as field values to STRUCT, it assumes you want an empty structure array with the given field names.
>> s=struct('a',{},'b',{})
s =
0x0 struct array with fields:
a
b
To pass an empty cell array as an actual field value, you would do the following:
>> s = struct('a',{{}},'b',{{}})
s =
a: {}
b: {}
Incidentally, any time you want to set a field value to a cell array using STRUCT requires that you encompass it in another cell array. For example, this creates a single structure element with fields that contain a cell array and a vector:
>> s = struct('strings',{{'hello','yes'}},'lengths',[5 3])
s =
strings: {'hello' 'yes'}
lengths: [5 3]
But this creates an array of two structure elements, distributing the cell array but replicating the vector:
>> s = struct('strings',{'hello','yes'},'lengths',[5 3])
s =
1x2 struct array with fields:
strings
lengths
>> s(1)
ans =
strings: 'hello'
lengths: [5 3]
>> s(2)
ans =
strings: 'yes'
lengths: [5 3]
ARGH... I think I found the answer. struct() has multiple behaviors, including:
Note If any of the values fields is
an empty cell array {}, the MATLAB
software creates an empty structure
array in which all fields are also
empty.
and apparently if you pass a member of a 0x0 structure as an argument, it's like some kind of empty phantom that doesn't really show up in the argument list. (that's still probably a bug)
bug2.m:
function bug2(arg1, arg2)
disp(sprintf('number of arguments = %d\narg1 = ', nargin));
disp(arg1);
test case:
>> nothing = struct('something',{})
nothing =
0x0 struct array with fields:
something
>> bug2(nothing,'there')
number of arguments = 2
arg1 =
>> bug2(nothing.something,'there')
number of arguments = 1
arg1 =
there
This behaviour persists in 2008b, and is in fact not really a bug (although i wouldn't say the designers intended for it):
When you step into add_something(S,'boing') and watch the first argument (say by selecting it and pressing F9), you'd get some output relating to the empty structure S.
Step into add_something(S.something,'test') and watch the first argument, and you'd see it's in fact interpreted as 'test' !
The syntax struct.fieldname is designed to return an object of type 'comma separated list'. Functions in matlab are designed to receive an object of this exact type: the argument names are given to the values in the list, in the order they are passed. In your case, since the first argument is an empty list, the comma-separated-list the function receives starts really at the second value you pass - namely, 'test'.
Output is identical in R2008b:
>> bug1
X=
str=
boing
X=
test
str=
??? Input argument "str" is undefined.
Error in ==> bug1>add_something at 11
disp(str);
Error in ==> bug1 at 4
add_something(S.something,'test'); % weird behavior