Specified key type does not match the type expected for this container matlab - 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'

Related

Matlab hash table with matrix key

I would like to construct a hash table in Matlab, the keys of which are matrices of different sizes, and the values of which are also matrices. The containers.Map class only allows strings as keys. I can certainly just use a cell for the keys, a cell for the value and match the indices of the two cells. Is there a better way to construct the hash table and the associated hash function?
I just played around with containers.Map a little, it seems that you can use char arrays of any length as keys.
>> a = containers.Map;
>> a(repmat('bla',50,500)) = 1;
>> a(repmat('bla',50,500))
ans =
1
You can also convert any numeric array into a char array as follows:
>> x = randn(4)
x =
-0.7371 -0.0799 0.1129 -1.1667
-1.7499 0.8985 0.4400 -1.8543
0.9105 0.1837 0.1017 -1.1407
0.8671 0.2908 2.7873 -1.0933
>> s = char(typecast(x(:),'uint8')')
s =
''uÔ_þ翼qÿû¿/å\¬"í?éúè#¿ë?.YðjÛs´¿Ó¶Ó·PÀì?+Ç? Õ9NÒ?Üéñé¼?
°À9-(Ü?ç¥ìƺ?NsivL#V*aó¨ªò¿{Ò5«ý¿Q8ß:#ò¿í=µU~ñ¿'
Or using the full 16-bit Unicode values allowed by char:
>> s = char(typecast(x(:),'uint16')')
s =
'疺㓦쁁뿛쓆遫뿅䅀庲뿋ꁰ頳劜㿡礋쮼㿘旈帡਑㿨ﮢ电玼㿼譍৊醪㿳랝趚蠷뿴瞶ꆲ쀂伴愹?㿬ꑨ꬞廆뿽㼝ὧ᛻㾱?ﺳ⩝㾢棑罓턽䀁ᕾ統렆뾱'
So putting these together, it is possible to use any array (properly converted to a char array) as key into a hash table:
>> a(s) = 5;
>> a(s)
ans =
5
And, given the numeric array cast to char, it is possible to cast it back to numeric array as well (though the shape of the array will get lost):
x = randn(1,20);
s = char(typecast(x,'uint8'));
y = typecast(uint8(s),'double');
assert(isequal(x,y)) % does not throw an error
There is another alternative. It is possible to use keys of type different from a string with containers.Map, as stated in the documentation. Keys can be either char arrays, or numeric scalars; they cannot be numeric arrays:
>> a = containers.Map('KeyType','double','ValueType','double');
>> a(5) = 10;
>> a([5,3]) = 5;
Error using containers.Map/subsasgn
Specified key type does not match the type expected for this container.
Thus, you could compute a hash value (as a floating-point double value or 64-bit integer value) from your arrays. How to best do this I don't know, maybe the dot product with a set of random values? At this related question there are some suggestions. There are also some functions on the MATLAB File Exchange that would be helpful (e.g. here and here).

getting list of values with list of keys for dictionary in 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]

How do I use containers.Map in Matlab with a cell array as the keys and a vector of integers as the values

I have a cell array that contains words like 'a', 'b', and 'c' for example. What I want to be able to do is use Matlab's containers.Map to make a hash table that I can add values to for each key and be able to look them up quickly. I am able to do this if I do not initialize my containers.Map object beforehand as follows but it does not allow me (or at least I haven't found a way) to add more key/value pairs later and makes it so that I have to reinitialize the object during each iteration of a loop:
key = {'a','b','c'};
newmap = containers.Map(key,[1,2,3]);
My problem is that I need to be able to continually add new keys to the hash table and therefore cannot keep initializing the containers.Map object each time, I want one long hash table with all the keys and values that I get while in a loop.
Here is the code that I am trying to get working, I want to be able to add the keys to the containers.Map object newmap and their corresponding values at the same time. The keys are always strings in a cell array and the values are always integers:
key = {'a','b','c'};
val = [1,2,3];
newmap = containers.Map(); % containers.Map object initialization
newmap(key) = val;
My desired output would something like this:
newmap(key)
ans = 1 2 3
Attempts at solving this:
I have tried converting the cell array of keys using cellstr() and char() but haven't had any luck with these. I seem to keep getting this error when trying this:
Error using containers.Map/subsref
Specified key type does not match the type expected for this container.
Thanks for any help.
% Initialize
map = containers.Map('KeyType','char','ValueType','double');
% Assume you get these incrementally
key = {'a','b','c'};
val = [1,2,3];
% Add incrementally
for ii = 1:numel(key)
map(key{ii}) = val(ii);
end
You can retrieve all values at once for a given set of keys, but you will get a cell array. No way around it, but you can convert with cell2mat(), or retrieve incrementally with a loop map(key{ii})
% Retrieve all
values(map,key)
ans =
[1] [2] [3]

Give value, return field name in matlab structure

I have a Matlab structure like this:
Columns.T21=6;
Columns.ws21=9;
Columns.wd21=10;
Columns.u21=11;
Is there some elegant way I can give the value and return the field name? For instance, if I give 6 and it would return 'T21.' I know that fieldnames() will return all the field names, but I want the fieldname for a specific value. Many thanks!
Assuming that the structure contains fields with scalar numeric values, you can use this struct2array based approach -
search_num = 6; %// Edit this for a different search number
fns=fieldnames(Columns) %// Get field names
out = fns(struct2array(Columns)==search_num) %// Logically index into names to find
%// the one that matches our search
Goal:
Construct two vectors from your struct, one for the names of fields and the other for their respective values. This has analogy to the dict in Python or map in C++, where you have unique keys being mapped to possibly non-unique values.
Simple Solution:
You can do this very simply using the various functions defined for struct in Matlab, namely: struc2cell() and cell2mat()
For the particular element of interest, say 1 of your struct Columns, get the names of all fields in the form of a cell array, using fieldnames() function:
fields = fieldnames( Columns(1) )
Similarly, get the values of all the fields of that element of Columns, in the form of a matrix
vals = cell2mat( struct2cell( Columns(1) ) )
Next, find the field with the corresponding value, say 6 here, using the find function and convert the resulting 1x1 cell into a char using cell2mat() function :
cell2mat( fields( find( vals == 6 ) ) )
which will yield:
T21
Now, you can define a function that does this for you, e.g.:
function fieldname = getFieldForValue( myStruct, value)
Advanced Solution using Map Container Data Abstraction:
You can also choose to define an object of the containers.map class using the field-names of your struct as the keySet and values as valueSet.
myMap = containers.Map( fieldnames( Columns(1) ), struct2cell( Columns(1) ) );
This allows you to get keys and values using corresponding built-in functions:
myMapKeys = keys(myMap);
myMapValues = values(myMap);
Now, you can find all the keys corresponding to a particular value, say 6 in this case:
cell2mat( myMapKeys( find( myMapValues == 6) )' )
which again yields:
T21
Caution: This method, or for that matter all methods for doing so, will only work if all the fields have the values of the same type, because the matrix to which we are converting vals to, need to have a uniform type for all its elements. But I assume from your example that this would always be the case.
Customized function/ logic:
struct consists of elements that contain fields which have values, all in that order. An element is thus a key for which field is a value. The essence of "lookup" is to find values (which are non-unique) for specific keys (which are unique). Thus, Matlab has a built-in way of doing so. But what you want is the other way around, i.e. to find keys for specific values. Since its not a typical use case, you need to write up your own logic or function for it.
Suppose your structure is called S. First extract all the field names into an array:
fNames=fieldnames(S);
Now define a following anonymous function in your code:
myfun=#(yourArray,desiredValue) yourArray==desiredValue;
Then you can get the desired field name as:
desiredFieldIndex=myfun(structfun(#(x) x,S),3) %desired value is 3 (say)
desiredFieldName=fNames(desiredFieldIndex)
Alternative using containers.Map
Assuming each field in the structure contains one scalar value as in the question (not an array).
Aim is to create a Map object with the field values as keys and the field names as values
myMap = containers.Map(struct2cell(Columns),fieldnames(Columns))
Now to get the fieldname for a value index into myMap with the value
myMap(6)
ans =
T21
This has the advantage that if the structure doesn't change you can repeatedly use myMap to find other value-field name pairs

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');