indexing for loop matlab - matlab

I want to do the following:
I create a matrix with all possible permutations from 1:n, for example
n=4;
L=perms(1:n)';
I get as output as expected a 4-by-24 matrix:
L =
Columns 1 through 13
4 4 4 4 4 4 3 3 3 3 3 3
3 3 2 2 1 1 4 4 2 2 1 1
2 1 3 1 2 3 2 1 4 1 2 4
1 2 1 3 3 2 1 2 1 4 4 2
Columns 14 through 24
2 2 2 2 2 1 1 1 1 1 1
3 4 4 1 1 3 3 2 2 4 4
1 3 1 4 3 2 4 3 4 2 3
4 1 3 3 4 4 2 4 3 3 2
Now I want to use this matrix for the indexes of a for loop:
Using the first column, I want to feed the input of my loop the following indexes: i=4 j=3,2,1. Then for i=3 j=2,1. Then for i=2 j=1. i=1 is empty
This could be done just for the first column like this:
for u=4:-1:1
for v=u-1:-1:1
But will not work for other columns so I need to do the same but with the entries of matrix L, something like (it doesn't work in MATLB) for column i=1:
u=L(1:4,1)
v=L(u:L(4,1) , 1) %// where u corresponds to L(1,1) then L(2,1) then L(3,1)
(for all the columns it would look like:
for i=1:length(L)
for u=L(4*(i-1)+1:4*i)
for v=.. ?
)
This doesn't work because MATLAB takes the values of the entries and when I write L(1,1):L(4,1) it doesn't mean return the entries from line one to line four but rather all the numbers with increment 1 from the value of L(1,1) to the value of L(4,1) (here empty).
Any ideas ? thank you very much in advance

I believe something like this will solve you problem.
for col = 1:size(L,2)
rowIdx = 1;
for j = [L(:,col)]'
for k = [L(rowIdx:end,col)]'
% Do your stuff here
end
rowIdx = rowIdx + 1;
end
end
Notice how I use the values from columns from L directly as loop index variable. In a for loop statement you can basically write any row vector and the index takes those values. For example
for i = [1, 7, 11, 14, 23]
disp(i); % prints 1,7,11,14,23
end
This is true for arrays of objects, cell arrays, basically any single row matrix.

You can do it like this:
for col = 1:size(L, 2)
for I = 1:n-1
for J = I:n
i = L(I,col);
j = L(J,col);
%// As an example just print out the loop variable values
disp(sprintf('Col:%d\ti:%d\tj:%d\r\n',col,i,j))
end
end
end

Related

Matlab removing duplicate matrix value

I have a matrix with a shape like below. I want to delete rows with duplicate values ​​in the first column and leaving row with the smallest number of duplicate values ​​in the second column. my matrix
`d =
1 1
2 1
4 1
8 2
2 2
5 4
2 4
6 4
7 3
`
I want to remove duplicate number 2 in the first column and leaving the row with the smallest number of duplicate values ​​in the second row
result required:
1 1
4 1
8 2
2 2
5 4
6 4
7 3
Thanks for the helps. best regard.
We can sort the array regards to first column and replace elements of second column by their descending count
to obtain this array:
1 3
2 3
2 3
2 2
4 3
5 3
6 3
7 1
8 2
Then if we apply unique to this array indices of desirable rows can be obtained and then then those rows can be extracted:
1 1
2 2
4 1
5 4
6 4
7 3
8 2
If oreder of original data should be preserved more step required that commented in the code.
a=[...
1 1
2 1
4 1
8 2
2 2
5 4
2 4
6 4
7 3];
%steps to replace counts of each element of column2 with it
[a2_sorted, i_a2_sorted] = sort(a(:,2));
[a2_sorted_unique, i_a2_sorted_unique] = unique(a2_sorted);
h = hist(a2_sorted, a2_sorted_unique);
%count = repelems(h, [1:numel(h); h]);%octave
count = repelem(h, h);
[~,a2_back_idx] = sort(i_a2_sorted);
count = count (a2_back_idx);
b = [a(:,1) , count.'];
%counts shoule be sorted in descending order
%because the unique function extracts last element from each category
[b_sorted i_b_sorted] =sortrows(b,[1 -2]);
[~, i_b1_sorted_unique] = unique(b_sorted(:,1));
c = [b_sorted(:,1) , a(i_b_sorted,2)];
out = c(i_b1_sorted_unique,:)
%more steps to recover the original order
[~,b_back_idx] = sort(i_b_sorted);
idx_logic = false(1,size(a,1));
idx_logic(i_b1_sorted_unique) = true;
idx_logic = idx_logic(b_back_idx);
out = c(b_back_idx(idx_logic),:)
Create a function that finds the minimal duplicate from the right column, given an index from the left column:
function Out = getMinDuplicate (Index, Data)
Candidates = Data(Data(:,1) == Index, :); Candidates = Candidates(:, 2);
Hist = histc (Data(:,2), [1 : max(Data(:,2))]);
[~,Out] = min (Hist(Candidates)); Out = Candidates(Out);
end
Call this function for all unique values in column 1:
>> [unique(d(:,1)), arrayfun(#(x) getMinDuplicate(x, d), unique(d(:,1)))]
ans =
1 1
2 2
4 1
5 4
6 4
7 3
8 2
(where d is your data array).

Matlab Matrix Repeat Value

my matrix:
e =
1 2
2 3
3 3
4 3
5 2
i want to repeat value from first coloumn as much as number from the second coloumn in the same row. i want to make my matrix to be like:
e =
1 2
1 2
2 3
2 3
2 3
3 3
3 3
3 3
4 3
4 3
4 3
5 2
5 2
thank you for your help...
You can use repelem to repeat the row indices and then grab those rows from e:
new_e = e(repelem(1:size(e,1), e(:,2)), :);
If you're using a MATLAB version prior to 2015a that doesn't have repelem, here's another way to do it:
spacing = cumsum([1; e(:,2)]); % the rows of new_e where we change row values
row_indices(spacing) = 1; % make a vector with these elements = 1
row_indices = cumsum(row_indices); % convert to row indices, last index is invalid
new_e = e(row_indices(1:end-1), :); % select valid rows from e

How can I go through the columns of a matrix in matlab and add them each to a specific column of a sum matrix in matlab?

Supose there is a Matrix
A =
1 3 2 4
4 2 5 8
6 1 4 9
and I have a Vector containing the "class" of each column of this matrix for example
v = [1 , 1 , 2 , 3]
How can I sum the columns of the matrix to a new matrix as column vectors each to the column of their class? In this example columns 1 and 2 of A would added to the first column of the new matrix, column 2 to the 3 to the 2nd, column 4 the the 3rd.
Like
SUM =
4 2 4
6 5 8
7 4 9
Is this possible without loops?
One of the perfect scenarios to combine the powers of accumarray and bsxfun -
%// Since we are to accumulate columns, first step would be to transpose A
At = A.' %//'
%// Create a vector of linear IDs for use with ACCUMARRAY later on
idx = bsxfun(#plus,v(:),[0:size(A,1)-1]*max(v))
%// Use ACCUMARRAY to accumulate rows from At, i.e. columns from A based on the IDs
out = reshape(accumarray(idx(:),At(:)),[],size(A,1)).'
Sample run -
A =
1 3 2 4 6 0
4 2 5 8 9 2
6 1 4 9 8 9
v =
1 1 2 3 3 2
out =
4 2 10
6 7 17
7 13 17
An alternative with accumarray in 2D. Generate a grid with the vector v and then apply accumarray:
A = A.';
v = [1 1 2 3];
[X, Y] = ndgrid(v,1:size(A,2));
Here X and Y look like this:
X =
1 1 1
1 1 1
2 2 2
3 3 3
Y =
1 2 3
1 2 3
1 2 3
1 2 3
Then apply accumarray:
B=accumarray([X(:) Y(:)],A(:)),
SUM = B.'
SUM =
4 2 4
6 5 8
7 4 9
As you see, using [X(:) Y(:)] create the following array:
ans =
1 1
1 1
2 1
3 1
1 2
1 2
2 2
3 2
1 3
1 3
2 3
3 3
in which the vector v containing the "class" is replicated 3 times since there are 3 unique classes that are to be summed up together.
EDIT:
As pointed out by knedlsepp you can get rid of the transpose to A and B like so:
[X2, Y2] = ndgrid(1:size(A,1),v);
B = accumarray([X2(:) Y2(:)],A(:))
which ends up doing the same. I find it a bit more easier to visualize with the transposes but that gives the same result.
How about a one-liner?
result = full(sparse(repmat(v,size(A,1),1), repmat((1:size(A,1)).',1,size(A,2)), A));
Don't optimize prematurely!
The for loop performs fine for your problem:
out = zeros(size(A,1), max(v));
for i = 1:numel(v)
out(:,v(i)) = out(:,v(i)) + A(:,i);
end
BTW: With fine, I mean: fast, fast, fast!

How to flip specific parts of a matrix

I am trying to flip certain parts of a matrix. I can explain better by example. Let's say that I have a matrix
M = [ 1 3 6;
1 2 4;
1 7 1;
2 9 0;
2 8 3;
2 4 2;
2 3 1;
3 6 5;
3 4 5;
3 1 9;
4 2 4;
4 8 6 ]
What I'd like to do here is take any rows with an even number in the first column, and flip the third column elements. The end result would look like this:
1 3 6
1 2 4
1 7 1
2 9 1 *
2 8 2 *
2 4 3 *
2 3 0 *
3 6 5
3 4 5
3 1 9
4 2 6 *
4 8 4 *
Note the rows marked with a star have had the elements of the third column flipped upside-down. The problem I'm having is going through each row like in a for-loop you cannot flip an entire set of rows.
Thanks in advance for any help.
Another time accumarray is the way to go:
A =[ 1 3 6 ;
1 2 4 ;
1 7 1 ;
2 9 0 ;
2 8 3 ;
2 4 2 ;
2 3 1 ;
3 6 5 ;
3 4 5 ;
3 1 9 ;
4 2 4 ;
4 8 6 ]
C = accumarray(A(:,1),A(:,3),[],#(x) {flipud(x)} ); %// get groups according to
%// first column and flip it
C = vertcat(C{:}); %// cell array returned,
%// transform to matrix
mask = ~mod(A(:,1),2); %// mask for even numbers
A(mask,3) = C(mask); %// replace masked values of 3rd column with flipped ones
returns:
A =
1 3 6
1 2 4
1 7 1
2 9 1
2 8 2
2 4 3
2 3 0
3 6 5
3 4 5
3 1 9
4 2 6
4 8 4
Certainly slower, but just for fun in two lines:
C = accumarray(A(:,1),A(:,3),[],#(x) {flipud(x)} );
A(~mod(A(:,1),2),3) = getfield( vertcat(C{:}), {~mod(A(:,1),2)});
%// well no, I won't explain it...
Edit: I assumed your first column just contains integers!
I would suggest you break the problem down into stages, something like so:
Identify blocks you wish to flip
Extract them
Flip them
Replace them
You can identify a set of even numbers using the unique and mod functions, then use a for loop over them and use logical indexing to pull/replace the blocks.
Here, try this
a = magic(5); % Some data in a 5x5 matrix
b = 1:numel(a); % Indices of <a>
Rearrange b however you want, then do a=a(b) to reassign a based on the reassigned indices of b. For example, the following code
disp(a(b));
would just return the elements of a in their original order. For your application this code should work:
a = <your matrix data>
b = 1:numel(a);
b = [b(1:27) fliplr(b(28:31)) b(32:34) fliplr(b(35:36))] % Change this part
a = reshape(a(b),size(a))
You should change b based on whatever you need it to do.

Sorting Coordinate Matrix in Matlab

In Matlab I have a big matrix containing the coordinates (x,y,z) of many points (over 200000). There is an extra column used as identification. I have written this code in order to sort all coordinate points. My final goal is to find duplicated points (rows with same x,y,z). After sorting the coordinate points I use the diff function, two consecutive rows of the matrix with the same coordinates will take value [0 0 0], and then with ismember I can find which rows of that matrix resulting from applying "diff" have the [0 0 0] row. With the indices returned from ismember I can find which points are repeated.
Back to my question...This is the code I wrote to sort properly my coordintes+id matrix. I guess It could be done better. Any suggestion?
%coordinates are always positive
a=[ 1 2 8 4; %sample matrix
1 0 5 6;
2 4 7 1;
3 2 1 0;
2 3 5 0;
3 1 2 8;
1 2 4 8];
b=a; %for checking purposes
%sorting first column
a=sortrows(a,1);
%sorting second column
for i=0:max(a(:,1));
k=find(a(:,1)==i);
if not(isempty(k))
a(k,:)=sortrows(a(k,:),2);
end
end
%Sorting third column
for i=0:max(a(:,2));
k=find(a(:,2)==i);
if not(isempty(k))
%identifying rows with same value on first column
for j=1:length(k)
[rows,~] = ismember(a(:,1:2), [ a(k(j),1),i],'rows');
a(rows,3:end)=sortrows(a(rows,3:end),1);
end
end
end
%Checking that rows remain the same
m=ismember(b,a,'rows');
if length(m)~=sum(m)
disp('Error while sorting!');
end
Why don't you just use unique?
[uniqueRows, ii, jj] = unique(a(:,1:3),'rows');
Example
a = [1 2 3 5
3 2 3 6
1 2 3 9
2 2 2 8];
gives
uniqueRows =
1 2 3
2 2 2
3 2 3
and
jj =
1
3
1
2
meaning third row equals first row.
If you need the full unique rows, including the fourth column: use ii to index a:
fullUniqueRows = a(ii,:);
which gives
fullUniqueRows =
1 2 3 9
2 2 2 8
3 2 3 6
Trying to sort a based on the fourth column? Do this -
a=[ 1 2 8 4; %sample matrix
1 0 5 6;
2 4 7 1;
3 2 1 0;
2 3 5 0;
3 2 1 8;
1 2 4 8];
[x,y] = sort(a(:,4))
sorted_a=a(y,:)
Trying to get the row indices having repeated x-y-z coordinates being represented by the first three columns? Do this -
out = sum(squeeze(all(bsxfun(#eq,a(:,1:3),permute(a(:,1:3),[3 2 1])),2)),2)>1
and use it similarly for sorted_a.