Finding corresponding values in double arrays in structure fields

22 views (last 30 days)
I have two structures in a for loop with i = 1:n
A(i).a
B(i).b
For each loop i, the field a of structure A contains a double array with r(i) rows and 1 column, and the field b of structure B contains a double array with r(i) rows and m columns. In other words, the number of rows of the double array in the field of each structure changes with i and it is the same for both structures and equal to r(i). Also, the number of columns in field a of structure A is fixed and equal to 1, and the number of columns in field b of structure B is fixed and equal to m.
For each loop i, I want to find out the column index for each row of the double array contained in field b of structure B of the element which has a value equal to the value of the element on the same row of the double array contained in field a of structure A. For each loop i, the result should be a double array with 1 column and a number of rows equal to the number of rows of the double array in each field. I want to store the result in a structure R(i).r.
I tried the following, but it only works when the number of rows of the double arrays is equal to 1. When the number of rows of the double arrays is >1, I get all kind of wrong numbers!
R(i).r = find(B(i).b(:,:) == A(i).a(:));
Thank you very much!
  5 Comments
Stephen23
Stephen23 on 16 May 2019
Giovanni Barbarossa's "Answer" moved here and formatted properly:
Jan,
thanks a lot for your assistance. I have attached the two structures A.a and B.b. If I use the code below
clear;
load AB
for n = 1:81;
R(n).r = find(A(n).a == B(n).b);
end
I get the structure R.r attached. You can note that "the code works" when the double array in B(n).b has only one row. For example, for n = 40, or n = 65 or n = 73. When the double array in B(n).b has more than one row, for example for n = 45 or n = 47 or n = 74, I get some meaningless numbers.
To be clear: "the code works" means that the codes correctly finds the column of the value in the row of the double array in B.b that is equal to the corresponding row value of the double array in A.a.
To be even more clear here is an example. For n = 40, the code does find in which column of the single row double array contained in B(40).b the value A(40).a = 16.8967 is. It does find that it is in column 14.
The code does not work for n = 45, in which case the double array A(45).a has 7 rows and R(45).r = [39;48;49;120;122;142;152] which is meaningless considering that the maximum number of columns of the double array contained in B(45).b is 22.
Thank you!
Stephen23
Stephen23 on 16 May 2019
Edited: Stephen23 on 16 May 2019
" I get some meaningless numbers."
"which is meaningless considering that the maximum number of columns of the double array..."
They are certainly not meaningless. As its documentation clearly states, with only one output argument find returns the linear indices (not column or row indices as you seem to assume).
"...the value A(40).a = 16.8967..."
Checking for equality of such values is very likely to fail due to floating point error issues. You should be using ismembertol or comparing the absolute difference against a tolerance.
As an aside, what is the point in using structure with just one field? Why not use a simpler container (e.g. a cell array)?

Sign in to comment.

Accepted Answer

Stephen23
Stephen23 on 16 May 2019
Edited: Stephen23 on 16 May 2019
Note that these methods assume that there is exactly one match per row. If this is not the case, then there is no way to distinguish how many matches each row has (unless you also store the row indices, or use linear indices, or find the closest values (e.g. min) rather than trying to find matching values, etc.).
Method One: difference and find:
for k = 1:81
% Difference of floating point numbers:
mat = bsxfun(@minus,A(k).a,B(k).b);
idx = abs(mat)<1e-5;
% Translate & get column&row indices:
[idc,idr] = find(idx.');
% Store column indices:
R(k).r = idc;
end
Checking:
>> A(45).a
ans =
12.021
12.355
12.371
13.352
2.696
13.119
13.743
>> B(45).b
ans =
Columns 1 through 10
2.0648 -0.76368 0.11314 2.3052 2.8992 3.5073 3.7053 6.2226 5.7135 4.8649
1.1811 1.1602 2.54 5.1009 6.8569 8.9056 8.6338 8.6547 9.052 7.9753
1.525 -0.49692 -0.068542 0.89102 2.1247 3.1357 3.4955 5.0548 4.8492 4.2495
3.3975 3.7438 9.1755 11.621 11.361 13.352 12.551 15.494 14.953 13.374
1.5649 1.7044 3.1453 3.7496 4.2454 4.2144 4.5398 4.7567 3.5637 2.4171
2.7443 1.2311 3.206 5.9502 6.4119 8.3098 13.119 14.773 18.197 17.504
1.8486 2.5462 2.4416 5.7551 8.0223 10.952 13.743 11.441 10.185 13.115
Columns 11 through 20
5.2326 7.0994 8.2874 10.607 11.116 11.215 11.102 12.021 12.742 12.261
7.3482 7.6304 6.9928 9.2296 8.7175 9.5746 9.2192 9.8882 10.954 10.902
3.4955 5.8773 6.854 7.6079 6.4599 9.7841 10.761 12.371 13.451 10.572
12.854 12.681 15.646 18.697 16.1 16.555 17.875 16.187 13.568 11.296
0.092961 -0.092963 2.0452 2.4636 1.7663 4.6948 1.7818 4.5863 5.6554 4.0905
18.851 20.518 21.634 21.211 19.441 21.07 22.262 23.634 25.507 23.788
13.812 11.615 15.068 18.591 19.114 22.707 21.904 25.044 26.822 25.183
Columns 21 through 22
13.067 12.374
12.355 12.93
11.618 10.966
10.863 6.5787
1.9213 2.696
26.661 24.481
24.695 20.893
>> R(45).r
ans =
18
21
18
6
22
7
7
>>
Method Two: ismembertol and ind2sub:
for k = 45
% Match floating point values:
idx = ismembertol(B(k).b,A(k).a);
% Translate & get column&row indices:
[idc,idr] = ind2sub(size(B(k).b.'),find(idx.'));
% Store column indices:
S(k).r = idc;
end
Checking:
>> S(45).r
ans =
18
21
18
6
22
7
7

More Answers (0)

Categories

Find more on Creating and Concatenating Matrices in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!