I have 2 cell arrays as below:
A = {'S' 'M' 'N' 'E'};
B = {'E' 'M' 'Q' 'S'};
In this case, the number of different elements is 3.
In a number array, I can use length(find(A ~= B)); to easily count number of different elements in one step easily.
Is there something similar for cell array of characters?
EDIT: I think I've misunderstood your question, and you probably meant finding different elements in corresponding positions in the arrays. I still kept my old answer
Counting different elements at the same position
yuk's approach with strcmp is correct. However, it works only if the two arrays are of the same size. The generalized solution would be:
N = min(numel(A), numel(B));
sum(~strcmp(A(1:N), B(1:N))) + numel(A) + numel(B) - 2 * N
If the arrays are of different length, the "extra" elements in the larger array will be counted as different here.
Counting different elements in any position
The most general approach would be using ismember, which does not care about lengths of strings or their position in the array. To count the total number of elements in A and B that are different, just do:
sum(ismember(A, B)) + sum(ismember(B, A))
The same effect can also be obtained with setdiff (instead of ismember):
numel(setdiff(A, B)) + numel(setdiff(B, A))
Both ways are valid for any two arrays, not necessarily of equal size.
Try
cell2mat(A)==cell2mat(B)
to start with, the rest should be straightforward. This simple approach will fail if the cell arrays don't have the same dimensions.
If your cell array is a cell array of strings you can use STRCMP:
sum(~strcmp(A,B))
Of course make sure A and B have the same length.
By the way for numeric array it's more efficient to use sum(A~=B). In general find is slow.
U can also try unique([A B]) if A and B are given in the exemple you gave.
It A and B do not have the same dimension you can try this.
unique(reshape(cell2mat(A,1,[])),reshape(cell2mat(B,1,[])))
Related
I'm really sorry to bother so I hope it is not a silly or repetitive question.
I have been scraping a website, saving the results as a collection in MongoDB, exporting it as a JSON file and importing it in MATLAB.
At the end of the story I obtained a struct object organised
like this one in the picture.
What I'm interested in are the two last cell arrays (which can be easily converted to string arrays with string()). The first cell array is a collection of keys (think unique products) and the second cell array is a collection of values (think prices), like a dictionary. Each field is an instance of possible values for a set of this keys (think daily prices). My goal is to build a matrix made like this:
KEYS VALUES_OF_FIELD_1 VALUES_OF_FIELD2 ... VALUES_OF_FIELDn
A x x x
B x z NaN
C z x y
D NaN y x
E y x z
The main problem is that, as shown in the image and as I tried to explain in the example matrix, I don't always have a value for all the keys in every field (as you can see sometimes they are 321, other times 319 or 320 or 317) and so the key is missing from the first array. In that case I should fill the missing value with a NaN. The keys can be ordered alphabetically and are all unique.
What would you think would be the best and most scalable way to approach this problem in MATLAB?
Thank you very much for your time, I hope I explained myself clearly.
EDIT:
Both arrays are made of strings in my case, so types are not a problem (I've modified the example). The main problem is that, since the keys vary in each field, firstly I have to find all the (unique) keys in the structure, to build the rows, and then for each column (field) I have to fill the values putting NaN where the key is missing.
One thing to remember you can't simply use both strings and number in one matrix. So, if you combine them together they can be either all strings or all numbers. I think all strings will work for you.
Before make a matrix make sure that all the cells have same element.
new_matrix = horzcat(keys,values1,...valuesn);
This will provide a matrix for each row (according to your image). Now you can use a for loop to get matrices for all the rows.
For now, I've solved it by considering the longest array of keys in the structure as the complete set of keys, let's call it keys_set.
Then I've created for each field in the structure a Map object in this way:
for i=1:length(structure)
structure(i).myMap = containers.Map(structure(i).key_field, structure(i).value_field);
end
Then I've built my matrix (M) by checking every map against the keys_set array:
for i=1:length(keys_set)
for j=1:length(structure)
if isKey(structure(j).myMap,char(keys_set(i)))
M(i,j) = string(structure(j).myMap(char(keys_set(i))));
else
M(i,j) = string('MISSING');
end
end
end
This works, but it would be ideal to also be able to check that keys_set is really complete.
EDIT: I've solved my problem by using this function and building the correct set of all the possible keys:
%% Finding the maximum number of keys in all the fields
maxnk = length(structure(1).key_field);
for i=2:length(structure)
if length(structure(i).key_field) > maxnk
maxnk = length(structure(i).key_field);
end
end
%% Initialiting the matrix containing all the possibile set of keys
keys_set=string(zeros(maxnk,length(structure)));
%% Filling the matrix by putting "0" if the dimension is smaller
for i=1:length(structure)
d = length(string(structure(i).key_field));
if d == maxnk
keys_set(:,i) = string(structure(i).key_field);
else
clear tmp
tmp = [string(structure(i).key_field); string(zeros(maxnk-d,1))];
keys_set(:,i) = tmp;
end
end
%% Merging without duplication and removing the "0" element
keys_set = union_several(keys_set);
keys_set = keys_set(keys_set ~= string(0));
I am trying to count the number of similar elements in two arrays, which can be done by the intersect function but I need to get only the values which are similar and have the same index. Any ideas?
If you are looking for how many entries in the two matrices are "nearly" the same, then set some tolerance tol, and then you want to find how many corresponding entries in your matrices (call them A and B) differ by less than tol.
abs(A-B)<tol
is a matrix the same size as A and B which has a 1 where the elements are close together, and a 0 where they're not. You can use
[i,j]=find(abs(A-B)<tol)
to get the positions of the nearly-mathcing elements, or
nnz(abs(A-B)<tol)
to just count how many values nearly-match.
I have a vector [x1, x2,...xn]. Is there a way to find all possible combinations of elements that contain the last element xn? For example, if I have 4 elements I want the combinations:
x1,x4
x2,x4
x3,x4
x1,x2,x3,x4
x1,x2,x4
x1,x3,x4
x2,x3,x4
In reality though I have number of elements up to a few hundreds.
Thank you for your time!
You really just need to do a choose on all of the elements except the last one.
C = cell(length(x)-1,1);
for n = 1:length(x)-1
C{n} = nchoosek(x(1:end-1),n);
end
Each element of C contains all possible vectors with n elements. All you have to do is tack onx(end) to each one to get what you're looking for. For example, if combo=C{4}(7,:) is one solved set without the last element of x, then your desired output is combo=[combo x(end)]. To do this for all solutions, just add this line of code inside the loop above:
C{n} = [C{n} x(end)*ones(size(C{n},1),1)];
WARNING: With thousands of elements you will run out of memory very quickly. Just 100 elements gives you over 6e29 possible combinations!
i have two matrices
r=10,000x2
q=10,000x2
i have to find out those rows of q which are one value or both values(as it is a two column matrix) different then r and allocate them in another matrix, right now i am trying this.i cannot use isequal because i want to know those rows
which are not equal this code gives me the individual elements not the complete rows different
can anyone help please
if r(:,:)~=q(:,:)
IN= find(registeredPts(:,:)~=q(:,:))
end
You can probably do this using ismember. Is this what you want? Here you get the values from q in rows that are different from r.
q=[1,2;3,4;5,6]
r=[1,2;3,5;5,6]
x = q(sum(ismember(q,r),2) < 2,:)
x =
3 4
What this do:
ismember creates an array with 1's in the positions where q == r, and 0 in the remaining positions. sum(.., 2) takes the column sum of each of these rows. If the sum is less than 2, that row is included in the new array.
Update
If the values might differ some due to floating point arithmetic, check out ismemberf from the file exchange. I haven't tested it myself, but it looks good.
I want to sum up several vectors of different size in an array. Each time one of the vectors drops out of my program, I want to append it to my array. Like this:
array = [array, vector];
In the end I want to let this array be the output of a function. But it gives me wrong results. Is this possible with MATLAB?
Thanks and kind regards,
Damian
Okay, given that we're dealing with column vectors of different size, you can't put them all in a numerical array, since a numerical array has to be rectangular. If you really wanted to put them in the numerical array, then the column length of the array will need to be the length of the longest vector, and you'll have to pad out the shorter vectors with NaNs.
Given this, a better solution would be, as chaohuang hinted at in the comments, to use a cell array, and store one vector in each cell. The problem is that you don't know beforehand how many vectors there will be. The usual approach that I'm aware of for this problem is as follows (but if someone has a better idea, I'm keen to learn!):
UpperBound = SomeLargeNumber;
Array = cell(1, UpperBound);
Counter = 0;
while SomeCondition
Counter = Counter + 1;
if Counter > UpperBound
error('You did not choose a large enough upper bound!');
end
%#Create your vector here
Array{1, Counter} = YourVectorHere;
end
Array = Array(1, 1:Counter);
In other words, choose some upper bound beforehand that you are sure you won't go above in the loop, and then cut your cell array down to size once the loop is finished. Also, I've put in an error trap in case you're choice of upper bound turns out to be too small!
Oh, by the way, I just noted in your question the words "sum up several vectors". Was this a figure of speech or did you actually want to perform a sum operation somewhere?