I want to know the index of row of cell consisting of particular array in particular column...
Example:
C{1,1} = [1 2 3];
C{1,2} = [4 5 6];
C{2,1} = [11 12 13];
C{2,2} = [14 15 16];
I want to get index as 1 when I search for [1 2 3] in column 1 (or) 2 when I search for [14 15 16] in column 2. I tried using
index = find([C{:,1}] == [1 2 3])
But didn't get. Please help
Use cellfun in combination with strfind and isempty or isequal directly.
pattern = [1 2 3];
out = cellfun(#(x) ~isempty(strfind(x,pattern)),C)
%// or as suggested by Luis Mendo
out = cellfun(#(x) isequal(x,pattern),C)
ind = find(out)
if the order within the arrays does not matter, also the following using
ismember and all is possible:
out = cellfun(#(x) all(ismember(x,pattern)),C)
out =
1 0
0 0
ind =
1
Do all the arrays have the same length n? Then you could use a more vectorized approach with an optional if-condition to see if your result is valid. It may is not necessary, depending how sure you are about your pattern input.
n = 3;
pos = strfind([C{:}],pattern)
ind = [];
if mod(pos,n) == 1, ind = (pos - 1)/n + 1, end
Both variants give you the linear index, means for pattern = [14 15 16]; it would return 4. To get the row indices you need an additional step:
[~,row_ind] = ind2sub(size(C),ind)
Another approach Using pdist2 instead of ismember and all from the other answer
pattern = [1 2 3];
out = cellfun(#(x) pdist2(x,pattern)==0,C);
ind = find(out)
Gives the same result as the other answer.
Related
I have two vectors, and I'm trying to find ALL coincidences of one on the other within a certain tolerance without using a for loop.
By tolerance I mean for example if I have the number 3, with tolerance 2, I will want to keep values within 3±2, so (1,2,3,4,5).
A = [5 3 4 2]; B = [2 4 4 4 6 8];
I want to obtain a cell array containing on each cell the numbers of all the coincidences with a tolerance of 1 (or more) units. (A = B +- 1)
I have a solution with zero units (A = B), which would look something like this:
tol = 0;
[tf, ia] = ismembertol(B,A,tol,'DataScale',1); % For tol = 0, this is equivalent to using ismember
idx = 1:numel(B);
ib = accumarray(nonzeros(ia), idx(tf), [], #(x){x}) % This gives the cell array
The output is:
ib =
[]
[]
[2 3 4]
[1]
Which is as desired.
If I change the tolerance to 1, the code doesn't work as intended. It outputs instead:
tol = 1
[tf, ia] = ismembertol(B,A,tol,'DataScale',1); % For tolerance = 1, this is equivalent to using ismember
idx = 1:numel(B);
ib = accumarray(nonzeros(ia), idx(tf), [], #(x){x}) % This gives the cell array
ib =
[5]
[2 3 4]
[]
[1]
When I would expect to obtain:
ib =
[2 3 4 5]
[1 2 3 4]
[2 3 4]
[1]
What am I doing wrong? Is there an alternative solution?
Your problem is that, in the current state of your code, ismembertol only outputs 1 index per element of B found in A, so you lose information in the cases where an element can be found several times within tolerance.
As per the documentation You can use the 'OutputAllIndices',true value pair argument syntax, to output what you want in ia with just a call to ismembertol:
A = [5 3 4 2]; B = [2 4 4 4 6 8];
tol = 0;
[tf, ia] = ismembertol(A,B,tol,'DataScale',1,'OutputAllIndices',true);
celldisp(ia) % tol = 0
ia{1} =
0
ia{2} =
0
ia{3} =
2
3
4
ia{4} =
1
celldisp(ia) % tol = 1
ia{1} =
2
3
4
5
ia{2} =
1
2
3
4
ia{3} =
2
3
4
ia{4} =
1
Here is a manual approach, just to provide another method. It computes an intermediate matrix of all absolute differences (using implicit expansion), and from the row and column indices of the entries that are less than the tolerance it builds the result:
A = [5 3 4 2];
B = [2 4 4 4 6 8];
tol = 1;
[ii, jj] = find(abs(A(:).'-B(:))<=tol);
ib = accumarray(jj, ii, [numel(A) 1], #(x){x});
Note that this approach
may be memory-intensive, because of the intermediate matrix;
can be made to work in old Matlab versions, because it doesn't use ismembertol; but then implicit expansion has to be replaced by explicitly calling bsxfun:
[ii, jj] = find(abs(bsxfun(#minus, A(:).', B(:)))<=tol);
ib = accumarray(jj, ii, [numel(A) 1], #(x){x});
I have made a table composed of four variables[v1, v2, v3, v4], with near 26000 rows. I need to search the values of an specific line e.g. [1 1 2 2016] within the table (26000 x 4), and return the index of the line in which the search is located.
Example of what I would like to search:
want_1 = [1 1 3 2016];
want_2 = [1 1 5 2016];
And would like to obtain the number of the line in which it is located.
If you have a matrix M (which you could get from table2array(T) on your table) you should be able to use implicit expansion* and all to get your result
srch = [1 1 3 2016]; % Row to search for
res = find( all( M == srch, 2 ) );
The find converts the logical array returned by all into the row numbers where it is true.
The implicit expansion here is basically the same as repeating the srch array for the entire height of the matrix M and then doing an element-wise == operation. The all then ensures that every comparison in a given row was true (i.e. a match for every element of srch).
*Implicit expansion relies on having MATLAB R2016b or newer... for older versions you can achieve the same using bsxfun.
Just as an exercise in alternatives, you could use splitapply instead to apply the all and == operators to each row in turn, this is probably slower...
res = find( splitapply( #(x)all(x==srch), M, (1:size(M,1)).' ) );
Or you could even use rowfun, which is a bit of a loop-in-disguise, but would work on your table T without having to first convert it to a matrix:
res = find( rowfun( #(varargin)all([varargin{:}]==srch), T, 'OutputFormat', 'uniform' ) );
For a matrix, you can use ismember with the 'rows' option:
M = [1 2 3 4; 1 1 3 2016; 5 6 7 8]; % example data matrix
wanted = [1 1 3 2016]; % example wanted row
result = find(ismember(M, wanted, 'rows'));
This also works with a table, as long as the wanted row is a table (of one row) with the same variable names:
M = table;
M.hour = [1; 2; 3]; M.day = [4; 5; 6]; M.month = [7; 8; 9]; M.year = [10; 11; 12];
wanted = table;
wanted.hour = 2; wanted.day = 5; wanted.month = 8; wanted.year = 11;
result = find(ismember(M, wanted, 'rows'));
I've always been told that almost all for loops can be omitted in MATLAB and that they in general slow down the process. So is there a way to do so here?:
I have a cell-array (tsCell). tsCell stores time-arrays with varying length. I want to find an intersecting time-array for all time-arrays (InterSection):
InterSection = tsCell{1}.time
for i = 2:length{tsCell};
InterSection = intersect(InterSection,tsCell{i}.time);
end
Here's another way. This also assumes there are no duplicates within each original vector.
tsCell_time = {[1 6 4 5] [4 7 1] [1 4 3] [4 3 1 7]}; %// example data (from Divakar)
t = [tsCell_time{:}]; %// concat into a single vector
u = unique(t); %// get unique elements
ind = sum(bsxfun(#eq, t(:), u), 1)==numel(tsCell_time); %// indices of unique elements
%// that appear maximum number of times
result = u(ind); %// output those elements
Here's a vectorized approach using unique and accumarray, assuming there are no duplicates within each cell of the input cell array -
[~,~,idx] = unique([tsCell_time{:}],'stable')
out = tsCell_time{1}(accumarray(idx,1) == length(tsCell_time))
Sample run -
>> tsCell_time = {[1 6 4 5],[4 7 1],[1 4 3],[4 3 1 7]};
>> InterSection = tsCell_time{1};
for i = 2:length(tsCell_time)
InterSection = intersect(InterSection,tsCell_time{i});
end
>> InterSection
InterSection =
1 4
>> [~,~,idx] = unique([tsCell_time{:}],'stable');
out = tsCell_time{1}(accumarray(idx,1) == length(tsCell_time));
>> out
out =
1 4
I am trying to create all possible 1xM vectors (word) from a 1xN vector (alphabet) in MATLAB. N is > M. For example, I want to create all possible 2x1 "words" from a 4x1 "alphabet" alphabet = [1 2 3 4];
I expect a result like:
[1 1]
[1 2]
[1 3]
[1 4]
[2 1]
[2 2]
...
I want to make M an input to my routine and I do not know it beforehand. Otherwise, I could easily do this using nested for-loops. Anyway to do this?
Try
[d1 d2] = ndgrid(alphabet);
[d2(:) d1(:)]
To parameterize on M:
d = cell(M, 1);
[d{:}] = ndgrid(alphabet);
for i = 1:M
d{i} = d{i}(:);
end
[d{end:-1:1}]
In general, and in languages that don't have ndgrid in their library, the way to parameterize for-loop nesting is using recursion.
[result] = function cartesian(alphabet, M)
if M <= 1
result = alphabet;
else
recursed = cartesian(alphabet, M-1)
N = size(recursed,1);
result = zeros(M, N * numel(alphabet));
for i=1:numel(alphabet)
result(1,1+(i-1)*N:i*N) = alphabet(i);
result(2:M,1+(i-1)*N:i*N) = recursed; % in MATLAB, this line can be vectorized with repmat... but in MATLAB you'd use ndgrid anyway
end
end
end
To get all k-letter combinations from an arbitrary alphabet, use
n = length(alphabet);
aux = dec2base(0:n^k-1,n)
aux2 = aux-'A';
ind = aux2<0;
aux2(ind) = aux(ind)-'0'
aux2(~ind) = aux2(~ind)+10;
words = alphabet(aux2+1)
The alphabet may consist of up to 36 elements (as per dec2base). Those elements may be numbers or characters.
How this works:
The numbers 0, 1, ... , n^k-1 when expressed in base n give all groups of k numbers taken from 0,...,n-1. dec2base does the conversion to base n, but gives the result in form of strings, so need to convert to the corresponding number (that's part with aux and aux2). We then add 1 to make the numbers 1,..., n. Finally, we index alphabet with that to use the real letters of numbers of the alphabet.
Example with letters:
>> alphabet = 'abc';
>> k = 2;
>> words
words =
aa
ab
ac
ba
bb
bc
ca
cb
cc
Example with numbers:
>> alphabet = [1 3 5 7];
>> k = 2;
>> words
words =
1 1
1 3
1 5
1 7
3 1
3 3
3 5
3 7
5 1
5 3
5 5
5 7
7 1
7 3
7 5
7 7
use ndgrid function in Matlab
[a,b] = ndgrid(alphabet)
I know that in MATLAB, in the 1D case, you can select elements with indexing such as a([1 5 3]), to return the 1st, 5th, and 3rd elements of a. I have a 2D array, and would like to select out individual elements according to a set of tuples I have. So I may want to get a(1,3), a(1,4), a(2,5) and so on. Currently the best I have is diag(a(tuples(:,1), tuples(:,2)), but this requires a prohibitive amount of memory for larger a and/or tuples. Do I have to convert these tuples into linear indices, or is there a cleaner way of accomplishing what I want without taking so much memory?
Converting to linear indices seems like a legitimate way to go:
indices = tuples(:, 1) + size(a,1)*(tuples(:,2)-1);
selection = a(indices);
Note that this is also implement in the Matlab built-in solution sub2ind, as in nate'2 answer:
a(sub2ind(size(a), tuples(:,1),tuples(:,2)))
however,
a = rand(50);
tuples = [1,1; 1,4; 2,5];
start = tic;
for ii = 1:1e4
indices = tuples(:,1) + size(a,1)*(tuples(:,2)-1); end
time1 = toc(start);
start = tic;
for ii = 1:1e4
sub2ind(size(a),tuples(:,1),tuples(:,2)); end
time2 = toc(start);
round(time2/time1)
which gives
ans =
38
so although sub2ind is easier on the eyes, it's also ~40 times slower. If you have to do this operation often, choose the method above. Otherwise, use sub2ind to improve readability.
if x and y are vectors of the x y values of matrix a, then sub2und should solve your problem:
a(sub2ind(size(a),x,y))
For example
a=magic(3)
a =
8 1 6
3 5 7
4 9 2
x = [3 1];
y = [1 2];
a(sub2ind(size(a),x,y))
ans =
4 1
you can reference the 2D matlab position with a 1D number as in:
a = [3 4 5;
6 7 8;
9 10 11;];
a(1) = 3;
a(2) = 6;
a(6) = 10;
So if you can get the positions in a matrix like this:
a([(col1-1)*(rowMax)+row1, (col2-1)*(rowMax)+row2, (col3-1)*(rowMax)+row3])
note: rowmax is 3 in this case
will give you a list of the elements at col1/row1 col2/row2 and col3/row3.
so if
row1 = col1 = 1
row2 = col2 = 2
row3 = col3 = 3
you will get:
[3, 7, 11]
back.