Sorting sub matrices based on specific column value

Hello All, I try to optimize the following code. I have this example fib_dist_ang matrix. First column numbers are not relevant to discussion. second column values are sorted while third column are not sorted.
I wanted to sort the third column values. This sorting is based on same value in the second column and place the value closest to the theta_ran (e.g. theta_ran =7.0) value. During this sorting based on the third row, In this example, lets confine discussion to last three rows we have to change the all values in the row (like how SORTROWS() command does). Output I requested is as follows:
Notes: 1) I had used UNIQUE to find the first and last rows of the repetitions based on the second column value. 2) To find the closest value, I had used histc.
fib_dist_ang=%required output
2 0.008 5.2
22 0.008 6.2
42 0.014 4.7
43 0.016 7.2
3 0.016 2.2
23 0.016 6.7
fib_dist_ang= %input
22 0.008 6.2
2 0.008 5.2
42 0.014 4.7
23 0.016 6.7
43 0.016 7.2
3 0.016 2.2
%FINDING THE INDICES OF THE REPETATIONS
[~,uniq_first,~] = unique(fib_dist_ang(:,2), 'first');
[~,uniq_last,~] = unique(fib_dist_ang(:,2), 'last');
tic_sortang=tic;
for i2=1:size(uniq_first,1)
%SORTING BASED ON THE THRID COLUMN VALUES IN THE SUB MATRIX
ithrow=sortrows(fib_dist_ang(uniq_first(i2):uniq_last(i2),:),3);
%FINDING CLOSEST VALUE, IF AVAILABLE
val=theta_ran; f=ithrow(:,3);
if val > f(1) && val < f(end) % it can find the closest angle
[N,bin]=histc(val,f);%if val < f(1), then bin=0.
index=bin+1;
if abs(val-f(bin))<abs(val-f(bin+1))
fclosest=f(bin); index=bin;
else
fclosest=f(index);
end
% PLACING THE CLOSEST VALE TO THETA_RAN, IF AVALABLE
ithrow=[ithrow(index,:);ithrow(1:index-1,:);ithrow(index+1:end,:) ];
end
%COPY BACK THE SUB MATRIX INTO THE WHOLE MATRIX.
fib_dist_ang(uniq_first(i2):uniq_last(i2),:)=ithrow;
end
Only this loop is taking almost half of my total program time. Hence, I am looking for any possibility to optimize this program.

4 Comments

How did you get this part :
43 0.016 7.2
3 0.016 2.2
23 0.016 6.7
How the third column is sorted?
Once we sort the third column, I am gonna search for a closest value to the theta_ran (in this example i defined theta_ran = 7, which is closest to 7.2). So I had placed 7.2 first.
For finding the closest value, I had used histc.
Ok, the closest is value is 7.2, after 7.2 it's 6.7, why in your result, you placed 2.2 in the second position?
Only first nearest value servers the purpose. I can place the 6.7 also after 7.2 and 2.2. But it is gonna take additional burden to code. So I am satisfied with 7.2, 2.2, 6.7.

Sign in to comment.

 Accepted Answer

I've not really tried to understand your code, nor have I run it, but if all you want to do is sort a column according to its distance to a certain value, then you simply need to sort according to abs(colvalue - referencevalue), so:
a = [22 0.008 6.2
2 0.008 5.2
42 0.014 4.7
23 0.016 6.7
43 0.016 7.2
3 0.016 2.2];
theta_ran = 7;
b = a;
b(:, 3) = abs(a(:, 3) - theta_ran);
[~, order] = sortrows(b, [2 3]); %sort first by 2nd column, then by distance from theta_ran in 3 rd column
a = a(order, :) %reorder a

2 Comments

I will try it out tomorrow and update you. It seems to give my expected result. Hope the values in the first column will also be changed due to the use of sortrows(). But not the values in the second column.
Thanks Guillaume. It served the purpose with simple logic.

Sign in to comment.

More Answers (1)

a=[22 0.008 6.2
2 0.008 5.2
42 0.014 4.7
23 0.016 6.7
43 0.016 7.2
3 0.016 2.2]
b=a;
b(:,4)=abs(b(:,3)-7)
[ii,jj,kk]=unique(a(:,2))
out=cell2mat(accumarray(kk,(1:numel(kk))',[],@(x) {sortrows(b(x,:),4)}))
out=out(:,1:3)

7 Comments

Thanks Azzi for your code. I am not able to get the sorted order for the first two rows from this code.
This is the result:
22.0000 0.0080 6.2000
2.0000 0.0080 5.2000
42.0000 0.0140 4.7000
43.0000 0.0160 7.2000
23.0000 0.0160 6.7000
3.0000 0.0160 2.2000
You were asking to sort the third column regarding to the closest value to 7 (6.2 then 5.2)
First is to get the sorted order of the third column (EDIT: based on the sorted second column values). And then if we have any value near to the theta_ran ( that is equal to 7), then the order should be based on the nearest value. Please see my main question, which gives the required output. Thanks! Edit: To be more clear, required output can be any one of the following:
2 0.008 5.2
22 0.008 6.2
42 0.014 4.7
43 0.016 7.2
3 0.016 2.2
23 0.016 6.7
or
2 0.008 5.2
22 0.008 6.2
42 0.014 4.7
43 0.016 7.2
23 0.016 6.7
3 0.016 2.2
Why isn't the order of the first 2 rows reversed? 6,2 is closer to 7 than 5.2
Yes Guillaume, You are correct. It should be sorted out as 6.2 and 5.2. Since, I was using histc previously, I was blinded.
a=[22 0.008 6.2
2 0.008 5.2
42 0.014 4.7
23 0.016 6.7
43 0.016 7.2
3 0.016 2.2]
b=a;
[ii,jj,kk]=unique(a(:,2));
q=accumarray(kk,(1:numel(kk))',[],@(x) {sortrows(a(x,:),3)});
s=cell2mat(q);
[~,idx]=min(abs(s(:,3)-7));
n=cumsum(cellfun(@(x) size(x,1) ,q));
jdx=find(idx<=n,1);
r=sortrows([q{jdx} abs(q{jdx}(:,3)-7)],4);
q{jdx}=r(:,1:3);
out=cell2mat(q)
Thanks Azzi for your revised code. It serves the purpose. However, this code is costly compared to accepted answer. However, I voted you for your efforts.

Sign in to comment.

Categories

Tags

Asked:

on 20 Feb 2016

Commented:

on 21 Feb 2016

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!