Help with a nested loop

1 view (last 30 days)
Erik J
Erik J on 12 Feb 2017
Commented: Guillaume on 12 Feb 2017
I am trying to create a function which loops through a data set by comparing each row to every other row, and returning a variable if a relationship between the two rows is true (in this case, a distance relationship). The function starts at row 2 and compares 2 to 3, 3 to 4, and so on, before the outer loop increases the starting row by 1, and then the function compares row 3 to row 2, row 3 to row 4, and so on, until every row is compared with every other row.
Currently, if I run this function without the outer loop, it seems to work fine. When I nest the inner loop in the outer loop to move the reference row by 1, it is not longer working properly.
There are two specific issues:
  • The nested loop I have written currently returns the entire vector of the variable I want returned only if the relationship between two rows is true. So if I tell the function to return x when the relationship is true, it is currently just returning the entire vector of x.
  • It is returning the entire vector of x as one long row. I would like it to return x (when the statement is true) but start a new row each time the outer loop repeats. So I end up with rows corresponding to all the values of x when I compared to row 2, a row of all the values when I compared to row 3, and so on.
Any help is much appreciated. I am still learning Matlab. Thank you. Here is the relevant chunk of code:
function [out] = EMA_location_compare(OutputVariable, Dist, xCartCoor, yCartCoor)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
len = length(xCartCoor); %number of rows
for n = 2:len %index reference row
for v = 2:len %index comparison row
if v == n
continue %skip iterations where n is compared with itself
elseif v ~=n
ipd = sqrt((xCartCoor(n) - xCartCoor(v))^2 + (yCartCoor(n) - yCartCoor(v))^2); %pythogrean distance
ipd = ipd * 1000; %convert kl to meters
if ipd <= (Dist) %if statement to define distance constraint
out(v) = OutputVariable(v); %output variable
end
end
end
end

Accepted Answer

Guillaume
Guillaume on 12 Feb 2017
The loops are not needed.
function out = EMA_location_compare(OutputVariable, Dist, xCartCoor, yCartCoor)
validateattribures(OutputVariable, {'numeric'}, {'vector'});
validateattributes(Dist, {'numeric'}, {'scalar', 'positive'});
validateattributes(xCartCoor, {'numeric'}, {'vector', 'size', size(OutputVariable)});
validateattributes(yCartCoor, {'numeric'}, {'vector', 'size', size(OutputVariable)});
%in R2016b:
d = hypot(xCartCoor - xCartCoor', yCartCoor - yCartCoor'); %calculate distance between all the points at once
%in version < R2016b
%d = hypot(bsxfun(@minus, xCartCoor, xCartCoor'), bsxfun(@minus, yCartCoor, yCartCoor')
[ref, comp] = find(d*1000 <= Dist);
out = accumarray(ref, OutputVariable(comp), [1 numel(OutpuVariable)], @(x){x});
end
The output is a cell array of vectors. out{i} contains all the OutputVariable values within distance of OutputVariable{i}.
The problem with your loop is that you're overwriting out(v) each time it matches an n. You could fix that in your original code with:
out = cell(size(xCartCoor)); %before the loop
for n = 2:numel(xCartCoor) %numel is safer than length
%...
out{v} = [out{v}, OutputVariable(v)];
%...
end
Also note, that
if somecond
%...
elseif oppositeofthesamecondition
%...
end
is simply
if somecond
%...
else
%...
end
But in your case,
if somecond
continue
else
%do something
end
would be better as
if ~somecond %i.e. if v ~= n
%comptue distance
end
  2 Comments
Erik J
Erik J on 12 Feb 2017
Hey, wow. Thank you. Your code works great and is much faster than looping.
One quick follow-up question: is it possible in the output to have all the output variables listed together in one large set, rather than have to open each individual cell to see the output for each row? Does that make sense?
Guillaume
Guillaume on 12 Feb 2017
"Listed together as one large set" would be a matrix, but with a matrix all rows must have the same number of elements. There's no guarantee that it'll be the case, so no.
You could pad the shorter rows with 0 or NaN to put it all in a matrix, but for further processing it would actually be harder to use. If you still want that:
maxlength = max(cellfun(@numel, out));
out = cell2mat(cellfun(@(v) [v, nan(1, maxlength - numel(v))], out, 'UniformOutput', false);

Sign in to comment.

More Answers (0)

Community Treasure Hunt

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

Start Hunting!