Asked by Mohammed Hammad
on 29 Mar 2019

Hello,

I have a struct with some fileds, (attached)

something like exp = {'Names', 'Date', 'X' , 'Y'}

Names = ['John', 'Adam', 'Markus',.....]

X = [ X1, X2, X3, X4,.....]

Y = [ Y1, Y2, Y3, Y4,.....]

I want to run an equation to calculate the sqrt for each two values depending on the same field (Date)

For Date (Date 1)

s12 = sqrt((X2-X1)^2+(Y2-Y1)^2);

then

s13= sqrt((X3-X1)^2+(Y3-Y1)^2);

and

s14= sqrt((X4-X1)^2+(Y4-Y1)^2);

and

s23 = sqrt((X3-X2)^2+(Y3-Y2)^2);

and

s24 = sqrt((X4-X2)^2+(Y4-Y2)^2);

and

s34 = sqrt((X4-X3)^2+(Y4-Y3)^2);

And the same for (Date2)

So I wrote a loop as follows:

for i= 1:length(example)

for j = i+1;

for u = 1:length(unique(example.dates,'rows'));

s(i) = sqrt((example(j).x-example(i).x)^2+(example(j).y-example(i).y)^2);

abr{i} = sprintf('%s-%s',strtrim(example(j).name),strtrim(example(i).name));

end

end

end

%%%%% Export results to an array (Date, Name i_Name j, S)

result = [];

for n = 1:length(unique(example.dates,'rows'));

result = [result; dates(n) abr(n) d(n)];

end

But I am sure there is something wrong because I should get s for all the pairs of the values and just for the same date each time.

The results should be something like that:

Please help me to figure out how to do that.

Answer by Stephen Cobeldick
on 29 Mar 2019

Edited by Stephen Cobeldick
on 29 Mar 2019

Accepted Answer

load example.mat

C = {example.Name};

D = {example.dates};

M = [example.x;example.y];

[U,~,idu] = unique(D);

N = max(idu);

fprintf('%-12s %-10s %-10s %s\n','Date','Name1','Name2','Result')

for k = 1:N

idf = find(idu==k);

P = nchoosek(1:numel(idf),2);

V = sqrt(sum((M(:,idf(P(:,1)))-M(:,idf(P(:,2)))).^2,1));

T = [repmat(U(k),size(V));C(idf(P(:,1)));C(idf(P(:,2)));num2cell(V)];

fprintf('%-12s %-10s %-10s %#.5g\n',T{:});

end

Which prints this in the command window:

Date Name1 Name2 Result

02-Apr-2002 John Adam 4.8237e+06

02-Apr-2002 John Markus 6.7899e+06

02-Apr-2002 John Ronny 7.4859e+06

02-Apr-2002 John Michael 3.8794e+06

02-Apr-2002 Adam Markus 5.9770e+06

02-Apr-2002 Adam Ronny 6.6450e+06

02-Apr-2002 Adam Michael 4.7198e+06

02-Apr-2002 Markus Ronny 7.3046e+05

02-Apr-2002 Markus Michael 2.9522e+06

02-Apr-2002 Ronny Michael 3.6236e+06

03-Apr-2002 Ronny Markus 5.9770e+06

03-Apr-2002 Ronny Michael 6.6450e+06

03-Apr-2002 Ronny John 4.8237e+06

03-Apr-2002 Ronny Adam 4.7198e+06

03-Apr-2002 Ronny Romio 5.8499e+05

03-Apr-2002 Ronny Sebastian 7.4353e+06

03-Apr-2002 Markus Michael 7.3046e+05

03-Apr-2002 Markus John 6.7899e+06

03-Apr-2002 Markus Adam 2.9522e+06

03-Apr-2002 Markus Romio 6.1503e+06

03-Apr-2002 Markus Sebastian 1.0072e+07

03-Apr-2002 Michael John 7.4859e+06

03-Apr-2002 Michael Adam 3.6236e+06

03-Apr-2002 Michael Romio 6.8414e+06

03-Apr-2002 Michael Sebastian 1.0753e+07

03-Apr-2002 John Adam 3.8794e+06

03-Apr-2002 John Romio 4.3132e+06

03-Apr-2002 John Sebastian 3.3172e+06

03-Apr-2002 Adam Romio 4.6077e+06

03-Apr-2002 Adam Sebastian 7.1300e+06

03-Apr-2002 Romio Sebastian 6.8562e+06

>>

And checking the last one:

>> sqrt((example(11).x-example(12).x).^2 + (example(11).y-example(12).y).^2)

ans =

6.8562e+06

>> example(11:12).Name

ans =

Romio

ans =

Sebastian

>> example(11:12).dates

ans =

03-Apr-2002

ans =

03-Apr-2002

Stephen Cobeldick
on 30 Mar 2019

"what is the best method (high performance) to save the results to one array (Date, Name1, Name2, V)?"

Preallocate a cell array before the loop, add the required data, then concatenate the contents after the loop. Something like this (untested, but should get you started):

Z = cell(1,N); % preallocate

for k = 1:N

...

Z{k} = T; % add data

end

Z = [Z{:}] % concatenate

"and if the equation changed to something else (any mathematical equation for the same x,y,z), does the structure of the code will be changed or just V!"

You would need to change the line that defines V:

V = ... new calculation here!

Just keep in mind that the calculation needs to accept a dims*columns matrix, and it needs to return a 1*columns row vector (where dims represent x, y, z, etc, and columns represents the number of instances of that date). Most likely you would write vectorized code:

Mohammed Hammad
on 30 Mar 2019

due to the large data that I have and it's difficult to check whether that's everything is alright, I changed my data to be as follows:

Multiple cells, each cell contains the same data but each cell express one date (unique).

For example:

Cell (02-Apr-2002) contains Date, Name, X, Y, Z

Cell (03-Apr-2002) contains Date, Name, X, Y, Z

And So on...

And I loaded them into my workspace:

myFolder ='......';

filePattern = fullfile(myFolder, '*.mat');

theFiles = dir(filePattern);

Headings = {'Date', 'Name', 'X', 'Y', 'Z'};

for i=1:length(theFiles)

eval(['load ' theFiles(i).name]);

array = cell2struct(data, Headings, 2);

end

C = {example.Name};

D = {example.dates};

M = [example.x;example.y];

[U,~,idu] = unique(D);

N = max(idu);

fprintf('%-12s %-10s %-10s %s\n','Date','Name1','Name2','Result')

%%%%% how to perform the loop to works on each file and export Z for each date %%%%%%

for n = 1:length(theFiles)

for k = 1:N

idf = find(idu==N);

P = nchoosek(1:numel(idf),2);

V = sqrt(sum((M(:,idf(P(:,1)))-M(:,idf(P(:,2)))).^2,1));

T = [repmat(U(k),size(V));C(idf(P(:,1)));C(idf(P(:,2)));num2cell(V)];

fprintf('%-12s %-10s %-10s %#.5g\n',T{:});

Z{k} = T;

end

end

I apprciate your help always

And I tried to make it something like :

for i=1:length(theFiles)

eval(['load ' theFiles(i).name]);

array = cell2struct(data, Headings, 2);

C = {example.Name};

D = {example.dates};

M = [example.x;example.y];

[U,~,idu] = unique(D);

N = max(idu);

fprintf('%-12s %-10s %-10s %s\n','Date','Name1','Name2','Result')

%%%%% how to perform the loop to works on each file and export Z for each date %%%%%%

for k = 1:N

idf = find(idu==N);

P = nchoosek(1:numel(idf),2);

V = sqrt(sum((M(:,idf(P(:,1)))-M(:,idf(P(:,2)))).^2,1));

T = [repmat(U(k),size(V));C(idf(P(:,1)));C(idf(P(:,2)));num2cell(V)];

fprintf('%-12s %-10s %-10s %#.5g\n',T{:});

Z{k} = T;

end

end

It runs good for a while with showing for each date all the required results but it stopped and it said:

Error using nchoosek (line 65) K must be an integer between 0 and N.

PS: I have around 2500 cells.

Stephen Cobeldick
on 31 Mar 2019

1. This loop:

for i=1:length(theFiles)

eval(['load ' theFiles(i).name]);

array = cell2struct(data, Headings, 2);

end

serves absolutely no purpose whatsoever, because you do not use any indexing (or concatenation) to store the output array, and so you simply overwrite array except for the one defined on the last iteration. So every previous iteration is just a waste of time. Also that eval usage should be avoided, which you can do very simply:

load(theFiles(i).name)

or even better:

S = load(theFiles(i).name);

array = cell2struct(S.data, Headings, 2);

2. You never use the variable array for anything anyway: once you have imported that data and created array you just ignore it. Seems like a waste of time to me!

3. For some reason you are still accessing a variable named example, although this is not defined anywhere in your code.

In any case that error message is very easy to understand: you will get that error whenever numel(idf)<2, i.e. there is only one name in the entire date group. If there is only one name (for a particular date) then clearly it is not possible to generate all combinations of two names from it! You will need to decide what to do in those cases (I cannot decide how your algorithm should work), but most likely you will need to add an IF condition, something like this:

Z = cell(1,N); % preallocate. Why did you remove this??? Very bad idea!

for k = 1:N

idf = find(idu==N);

if numel(idf)>1

... your code

Z{k} = T; % add data

else

... decide what you want to do with zero/one names.

end

end

Z = [Z{:}] % concatenate

Depending on how you decide to handle the one-name groups, you might need to use indexing for the concatenation as well.

Sign in to comment.

Opportunities for recent engineering grads.

Apply Today
## 4 Comments

## Stephen Cobeldick (view profile)

## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/453276-matlab-function-for-each-two-values-in-struct-inside-loop#comment_687576

## Mohammed Hammad (view profile)

## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/453276-matlab-function-for-each-two-values-in-struct-inside-loop#comment_687633

## Luna (view profile)

## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/453276-matlab-function-for-each-two-values-in-struct-inside-loop#comment_687640

## Mohammed Hammad (view profile)

## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/453276-matlab-function-for-each-two-values-in-struct-inside-loop#comment_687644

Sign in to comment.