51

Suppose I have the following matrix:

01 02 03 06
03 05 07 02
13 10 11 12
32 01 08 03

And I want the indices of the top 5 elements (in this case, 32, 13, 12, 11, 10). What is the cleanest way to do this in MATLAB?

Mad Scientist
  • 18,090
  • 12
  • 83
  • 109
Vlad the Impala
  • 15,572
  • 16
  • 81
  • 124
  • 2
    One clarification: How would you want to deal with repeated elements? For example, if the number 32 appeared 7 times, would you want to get indices for all 7, or just five of them, or just 1 of them and then indices for the next 4 largest elements? – gnovice Apr 22 '10 at 16:26
  • 1
    @Eric Leschinski Please don't add tags to titles, it is not necessary and generally discouraged by the community (see [this meta post for the official answer on this topic](http://meta.stackexchange.com/a/5069/151385)) – Mad Scientist Jan 18 '13 at 07:33

4 Answers4

78

There are a couple ways you can do this depending on how you want to deal with repeated values. Here's a solution that finds indices for the 5 largest values (which could include repeated values) using sort:

[~, sortIndex] = sort(A(:), 'descend');  % Sort the values in descending order
maxIndex = sortIndex(1:5);  % Get a linear index into A of the 5 largest values

Here's a solution that finds the 5 largest unique values, then finds all elements equal to those values (which could be more than 5 if there are repeated values), using unique and ismember:

sortedValues = unique(A(:));          % Unique sorted values
maxValues = sortedValues(end-4:end);  % Get the 5 largest values
maxIndex = ismember(A, maxValues);    % Get a logical index of all values
                                      %   equal to the 5 largest values
gnovice
  • 125,304
  • 15
  • 256
  • 359
  • 1
    Actually, there is no need to do the last step posed by gnovice. The second output of sort is a list of tags for the sort. So the index of those selected values is given by the corresponding tags from the sort. If you wish for the index in terms of a pair of subscripts, then call ind2sub. –  Apr 22 '10 at 16:27
  • @woodchips: Good catch. I was in the process of changing it as you commented, as well as adding another option to deal with repeated values in a different way. – gnovice Apr 22 '10 at 16:37
  • 3
    This method is probably the cleanest for small matrices, but clearly sub-optimal for large matrices since sorting scales like O(N*log(N)) while doing it the "non Matlab way" would scale like O(N). – Adrien Apr 22 '10 at 16:49
  • 2
    UNIQUE already returns sorted values and in vector format, so just `unique(A)` in the first line should work. – yuk Apr 22 '10 at 16:54
  • Thanks for a very concise and accurate answer to this question. You helped me out a lot! – Malcolm Feb 10 '12 at 01:45
17

If you have a rather big array and only want a few elements out of it. This would be my solution.

Arraycopy = Array;
for j = 1:n
   [a, Index(j)] = max(Arraycopy);
   Arraycopy(Index(j)) = -inf;
end
maximumValues = Array(Index);

I think it should be faster and less RAM demanding than the sort solution.

Kijewski
  • 25,517
  • 12
  • 101
  • 143
Sebastian
  • 179
  • 1
  • 2
  • 2
    This works only if the n largest elements are larger than 0. Otherwise replace 0 by min(Arraycopy, ...). – Unapiedra Dec 14 '12 at 11:45
7

You can find good answers to matlab questions also on matlabcentral. I found a good mex implementation there while searching for the same thing.

It is done by Bruno Luong using a partial quick-sort algorithm implemented with C-MEX. The complexity is O(n + k.log(k)), where n is the size of the array, and k is the number of elements to be selected. It is faster than SORT or multiple call of MIN/MAX for large size inputs. Multidimensional capability supported

http://www.mathworks.com/matlabcentral/fileexchange/23576-minmax-selection

seviyor
  • 96
  • 1
  • 3
5

In MATLAB ≥ R2017b, you can use maxk for this specific purpose.

[maxvalues, ind] = maxk(A(:), 5);
Sardar Usama
  • 19,536
  • 9
  • 36
  • 58
  • 1
    Nice! It looks like it has the same behavior as the first solution in my answer (i.e. the output can include repeated values). – gnovice Jul 18 '18 at 13:27