Consider the following arrays:
A = [1 3 4 5 6 7 1 3 7];
B = [1 4 7];
I want to find all elements of B in array A. So, my final output array will look something like:
C = [1 7 3 6 9];
First element of B is at locations 1 and 7 in array A, so C has 1 and 7 as first two elements. Element 4 of B is at location 3, so array C has 3 as its third element and so on.
The order of C is required?
Fast, but another order:
find(ismember(A,B))
Slower, but the order you want:
cell2mat(arrayfun(#(x)(find(A==x)),B,'UniformOutput',false))
Basically, the second solution iterates over all elements of B and applies find(A==x) in a loop.
You may also delete the cell2mat, then a cell is returned. First element -> Occurrences of 1, second element-> occurrences of 4 etc.
If you need the result in that order: you can use the two outputs of ismember. This may be faster than Daniel's answer (second part) as it avoids arrayfun:
[tf, loc] = ismember(A,B);
loc = loc(tf);
ind = find(tf);
[~, order] = sort(loc);
C = ind(order);
Second output of ismember will give a map for each element of B
>> [~,ic] = ismember(A,B)
ic =
1 0 2 0 0 3 1 0 3
Then element-wise test against each element of B:
>> [C,~] = find(bsxfun(#eq,ic.',1:numel(B)))
C =
1
7
3
6
9
And because I'm require to do so, an alternative method following ismember:
c = accumarray(nonzeros(ic),find(ic),[],#(x) {sort(x)});
C = vertcat(c{:})
Related
I want to find all possible variations (combinations) of a vector, choosing various numbers of elements from that vector.
For example, suppose I have the vector:
x = [1 2 3 4 5];
I can determine the number of combinations for each number of chosen elements:
x = [1 2 3 4 5]';
n = numel(x);
for k = 1:n
combs(k) = nchoosek(n,k);
end
sum(combs)
This results in:
combs = 5 10 10 5 1
sum(combs) = 31
I want a way to store all 31 of these combinations in an array, for example a cell array, with n cells, within each is an array in which each row is a vector combination of the elements.
e.g. at k = 4:
combs{4} =
1 2 3 4
1 2 3 5
1 2 4 5
1 3 4 5
2 3 4 5
Is there an existing function that does this, or what would be the most simple approach to this?
Call nchoosek with a vector as first input, using arrayfun (or equivalently for) to loop over the number of picked elements:
n = 5;
combs = arrayfun(#(k) nchoosek(1:n,k), 1:n, 'UniformOutput', false);
Here is an approach using dec2bin , find and accumarray:
x = [1 2 3 4 5];
[a b] = find(dec2bin(1:2^numel(x)-1)=='1');
combs = accumarray(a,x(b),[],#(c){c});
What I'm trying to do: given a 2D matrix, get the column indices of the elements in each row that satisfy some particular condition.
For example, say my matrix is
M = [16 2 3 13; 5 11 10 8; 9 7 6 12; 4 14 15 1]
and my condition is M>6. Then my desired output would be something like
Indices = {[1 4]'; [2 3 4]'; [1 2 4]'; [2 3]';}
After reading the answers to this similar question I came up with this partial solution using find and accumarray:
[ix, iy] = find(M>6);
Indices = accumarray(ix,iy,[],#(iy){iy});
This gives very nearly the results I want -- in fact, the indices are all right, but they're not ordered the way I expected. For example, Indices{2} = [2 4 3]' instead of [2 3 4]', and I can't understand why. There are 3 occurrences of 2 in ix, at indices 3, 6, and 9. The corresponding values of iy at those indices are 2, 3, and 4, in that order. What exactly is creating the observed order? Is it just arbitrary? Is there a way to force it to be what I want, other than sorting each element of Indices afterwards?
Here's one way to solve it with arrayfun -
idx = arrayfun(#(x) find(M(x,:)>6),1:size(M,1),'Uni',0)
Display output wtih celldisp(idx) -
idx{1} =
1 4
idx{2} =
2 3 4
idx{3} =
1 2 4
idx{4} =
2 3
To continue working with accumarray, you can wrap iy with sort to get your desired output which doesn't look too pretty maybe -
Indices = accumarray(ix,iy,[],#(iy){sort(iy)})
Output -
>> celldisp(Indices)
Indices{1} =
1
4
Indices{2} =
2
3
4
Indices{3} =
1
2
4
Indices{4} =
2
3
accumarray is not guaranteed to preserve order of each chunk of its second input (see here, and also here). However, it does seem to preserve it when the first input is already sorted:
[iy, ix] = find(M.'>6); %'// transpose and reverse outputs, to make ix sorted
Indices = accumarray(ix,iy,[],#(iy){iy}); %// this line is the same as yours
produces
Indices{1} =
1
4
Indices{2} =
2
3
4
Indices{3} =
1
2
4
Indices{4} =
2
3
Hi I have a correlation Matrix:
A = [1 2 1 3 1 2 4 3 5 1;
2 3 4 5 6 6 6 7 7 8];
I need to find out how many times each individual element of row 1 is linked to elements in row 2.
For example, here element 1 in row 1 is related to the following elements of row 2, {2, 4, 6, 8}, so total 4 elements.
Similarly 2 is linked to {3, 6}, for a total of 2 elements.
Resulting Matrix C should be:
[element name in 1st row; Number of connection].
In previous example, C = [1 2 ....; 4 2 ...];
Since actual matrix size is of the order of 1000s', it is impossible to do manually. Any help will be appreciated.
There is probably a way to do this without resorting to a for loop but this is one solution I can think of right now. Identify the unique elements in the first row of matrix A and loop over all the elements to find the ones they are linked to in the second row.
I have assumed that you only need to identify the unique elements that the first row is linked to, hence the unique() function inside the for loop; if that is not the case, please remove that from the code.
a = [1 2 1 3 1 2 4 3 5 1; 2 3 4 5 6 6 6 7 7 8];
row1el = unique(a(1, :));
c = zeros(2, length(row1el));
for i = 1:length(row1el)
idx = a(1, :) == row1el(i);
linkedEl = a(2, idx);
c(1, i) = row1el(i);
c(2, i) = length(unique(linkedEl));
end
disp(c)
If I understood the question properly, you are not really concerned about the values in the second row, but the number of occurrences of the elements in row 1. This can be obtained with the unique and histc functions:
C(1,:)=unique(A(1,:));
C(2,:)=histc(A(1,:),C(1,:));
C =
1 2 3 4 5
4 2 2 1 1
The answer depends on whether repeated columns should be counted repeatedly or not. Consider the following data:
A = [1 2 1 3 1 2 4 3 5 1;
2 3 4 5 6 6 6 5 7 8]; %// col [3;5] appears twice
If repeated columns should be counted according to their multiplicity: you can use accumarray:
[ii, ~, kk] = unique((A(1,:)));
jj = accumarray(kk.', A(2,:).', [], #(x) numel(x)).';
C = [ii; jj];
Result with my example A:
C =
1 2 3 4 5
4 2 2 1 1
Or you can use sparse:
[~, ii, jj] = find(sum(sparse(A(2,:), A(1,:), 1)));
C = [ii; jj];
The result is the same as above.
If repeated columns should be counted just once: either of the two approaches is easily adapted to this case:
[ii, ~, kk] = unique((A(1,:)));
jj = accumarray(kk.', A(2,:).', [], #(x) numel(unique(x))).'; %'// note: "unique"
C = [ii; jj];
or
[~, ii, jj] = find(sum(sparse(A(2,:), A(1,:), 1) > 0)); %// note: ">0"
C = [ii; jj];
Result (note third column is different than before):
C =
1 2 3 4 5
4 2 1 1 1
I’ve a matrix A = (4*4) and a cell array B {4,1}. I’d like to find all the values of B in A, searching row by row and after I’d like to delete the correspondent column associated to this particular value. I’ve a problem using bsxfun o cellfun and find function with a matrix and a cell array. I‘ve tried to convert the cell array into a matrix but I don’t have more the exact correspondence.
For example:
A =
1 5 10 23
2 4 2 18
3 3 5 14
1 9 10 4
B =
1
2 4
3 3 14
1
To obtain:
C =
10
2
5
10
Thanks in advance,
L.
Here's how:
C = cellfun(#(x, y){sparse(1,find(ismember(x,y),numel(y)),true,1,size(A,2))}, ...
mat2cell(A, ones(size(A, 1), 1), size(A, 2)), B(:));
C = A(:, all(~vertcat(C{:})));
The cellfun is fed with two cell arrays: the first one contains the rows of A and second one is B. The anonymous function is the tricky part; it operates on a pair of two corresponding rows as follows:
It employs ismember to check which columns in A contain any of the elements in B.
It uses find to pick only the first N ones, with respect to the number of elements in the B.
It uses sparse as a fancy way of zeroing out the rest of the elements.
For your example it would look like this:
A = [1 5 10 23; 2 4 2 18; 3 3 5 14; 1 9 10 4];
B = {1; [2 4]; [3 3 14]; 1};
C = cellfun(#(x, y){sparse(1,find(ismember(x,y),numel(y)),true,1,size(A,2))}, ...
mat2cell(A, ones(size(A, 1), 1), size(A, 2)), B(:));
which yields:
C =
{
[1 0 0 0]
[1 1 0 0]
[1 1 0 1]
[1 0 0 0]
}
After that, it's a simple matter of logical indexing to pick the resulting columns:
C = A(:, all(~vertcat(C{:})));
which in this case should be:
C =
10
2
5
10
I woutld like to split an array into equal pieces like this:
a=[1 2 3 4 5 6 7 8 9 10]
n = 2;
b = split(a, n);
b =
1 2 3 4 5
6 7 8 9 10
Which function can do this?
Try this:
a = [1 2 3 4 5 6]
reshape (a, 2, 3)
If a can be divided by n you can actually provide only one argument to RESHAPE.
To reshape to 2 rows:
b = reshape(a,2,[])
To reshape to 2 columns:
b = reshape(a,[],2)
Note that reshape works by columns, it fills the 1st column first, then 2nd, and so on. To get the desired output you have to reshape into 2 columns and then transpose the result.
b = reshape(a,[],2)'
You can place a check before reshape:
assert(mod(numel(a),n)==0,'a does not divide to n')