Extract indices of two related arrays based on uniqueness and minimum WITHOUT FOR LOOP
2 Ansichten (letzte 30 Tage)
Ältere Kommentare anzeigen
Still Learning Matlab
am 22 Jun. 2018
Bearbeitet: Jan
am 23 Jun. 2018
I have two arrays, A and B, whose indices relate to inputs of an analysis (i.e. A(1) and B(1) are two tracked outputs of run 1 of a simulation with distinct inputs, A(7) and B(7) correspond to the 7th run, whose inputs vary from all other runs).
A B
0.5 1
0.75 1
0.75 3
1 7
0.5 4
0.75 9
1 2
1 6
0.5 1
I am trying to create a vector of indices which tracks all minimum values of B for each unique value of A So from the above example the desired output is
index
1
2
8
10
*Note that if there are multiple indices which have the minimum value of B for the same value of A, i want to keep both indices.
I am currently using a for loop (below), but because my array A and B are extremely large (1*10^8 entries) it take hours to run the script
%Extract unique elements of A
Unique_A = unique(A);
%preallocate index vector for speed (no clue how big this will be so intentionally large
Alternative_index = zeros(1*10^6,1);
for i = 1:length(Unique_A)
% Find the indices of the Benefit vector which correspond to a each unique value of A
indices = find(A==Unique_A(i));
%Now determine which of the corresponding indices in B are equal to the minimum value
min_B_indices = (indices(B(indices)== min(B(indices))))
%since the index vector was pre allocated, I need to make sure I am appending the vector without overwriting entries. So determine how many entries will need to be appended:
length_of_append = length(min_B_indices)
%Now find the first zero element of the preallocated vector
first_zero = find(Alternative_index==0, 1, 'first')
%Now add the indices to the preallocated vector
Alternative_index(first_zero:first_zero+length_of_append-1,1) = min_B_indices;
end
%remove trailing zeros
Alternative_index = Alternative_index(Alternative_index~=0);
I have wracked my brain on how to do this without a for loop...anyone have a suggestion?
3 Kommentare
Matt J
am 22 Jun. 2018
from the above example the desired output is index 1 2 8 10
How are you able to get an index of 10 in the example output when your A,B are only 9 elements long?
Akzeptierte Antwort
Jan
am 22 Jun. 2018
Bearbeitet: Jan
am 23 Jun. 2018
A leaner version using a cell instead of a pre-allocation:
A = randi([1,1000], 1, 1e6);
B = randi([1,1000], 1, 1e6);
uniqA = unique(A);
OutC = cell(1, length(uniqA));
for i = 1:length(uniqA)
index = find(A == uniqA(i));
BB = B(index);
OutC{i} = index(BB == min(BB));
end
Out = cat(2, OutC{:}).';
It takes 1.60 sec instead of 2.25 sec for the original code.
But Matt J's splitapply approach takes 0.33 sec:
G = findgroups(A);
C = 1:numel(B);
OutC = splitapply(@(b,c) {c(b==min(b))}, B, C, G);
Out = cat(2, OutC{:}).';
1 Kommentar
Siehe auch
Kategorien
Mehr zu Loops and Conditional Statements finden Sie in Help Center und File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!