Let's say A
is a 200 item cell array containing 4 different strings (each has 50 repetitions).
B
is a 200 item vector with some integers.
I'm using [cellNos cellStartInd enumCells ] = unique(A)
and get which item in开发者_如何学编程 A
is equal to one of the unique strings (enumCells is an array containing integers 1-4, sort of enumerating the strings).
I want to use this information to create a 4x50 matrix of values from B
so that each column will have the values for a specific unique string. In other words, I want to reshape B
into a matrix where the columns were arranged according to each unique string in A
.
Assuming that you know already how many repetitions there will be, and that all strings are repeated with equal frequency, you can do the following:
%# sort to find where the entries occur (remember: sort does stable sorting)
[~,sortIdx] = sort(enumCells);
%# preassign the output to 50-by-4 for easy linear indexing
newB = zeros(50,4);
%# fill in values from B: first the 50 ones, then the 50 2's etc
newB(:) = B(sortIdx);
%# transpose to get a 4-by-50 array
newB = newB';
Or, in a more compact fashion (thanks @Rich C)
[~,sortIdx] = sort(enumCells);
newB = reshape(B(sortIdx),50,4)';
For the general case where you have N
different strings and each of these strings occurs a different number of times M_i
, then each corresponding set of values in B
will have a different length and you won't be able to concatenate the sets together into a numeric array. You will instead have to store the sets in an N
-element cell array, and you can do this using the functions UNIQUE and ACCUMARRAY:
>> A = {'a' 'b' 'b' 'c' 'a' 'a' 'a' 'c' 'd' 'b'}; %# Sample array A
>> B = 1:10; %# Sample array B
>> [uniqueStrings,~,index] = unique(A)
>> associatedValues = accumarray(index(:),B,[],@(x) {x})
associatedValues =
[4x1 double] %# The values 1, 5, 6, and 7
[3x1 double] %# The values 2, 3, and 10
[2x1 double] %# The values 4 and 8
[ 9] %# The value 9
In the specific case where each string occurs the same number of times the above code will still work just fine, and you will have the option of converting the output from a cell array to the desired numeric array like so:
associatedValues = [associatedValues{:}];
NOTE: Since ACCUMARRAY is not guaranteed to maintain the relative order of items it accumulates, the order of items within the cells of associatedValues
may not match the relative order they had in the vector B
. One way to ensure that the original relative order in B
is maintained is to modify the call to ACCUMARRAY as follows:
associatedValues = accumarray(index(:),1:numel(B),[],@(x) {B(sort(x))});
Or you could sort the inputs to ACCUMARRAY to get the same effect:
[index,sortIndex] = sort(index);
associatedValues = accumarray(index(:),B(sortIndex),[],@(x) {x});
If I understand your question correctly, this can be done using the find function. http://www.mathworks.com/help/techdoc/ref/find.html
To create your matrix, just write:
M(:,1) = B(find(enumCells==1));
M(:,2) = B(find(enumCells==2));
M(:,3) = B(find(enumCells==3));
M(:,4) = B(find(enumCells==4));
There's probably a more elegant way to do it, but this should work.
EDIT: You could try using "sort" to do it. The sort function can give the permutations of the sorting as output. Try:
[s perm] = sort(enumCells);
M = reshape(B(perm),50,4);
This method will work if the number of entries per string is the same, if they vary see @gnovice solution.
NumStrings = numel(CellNos);
M = zeros(size(B,1)/NumStrings,NumStrings);
for i = 1:NumStrings
M(:,i) = B(strcmp(B,CellNos{i}));
end
Also, if you know what the unique strings are ahead of time (ie CellNos}, this allows you to skip the unique call, which is relatively expensive.
精彩评论