2

For no particular reason I would like to know if it's possible to select the n number of biggest value in an array or matrix, all in a oneliner.

Say I have array:

A=randn(1,100);

And I want the biggest, e.g., 20 values, preferably ordered from high to low. So far I have the 2-liner:

A_ordered = sort(A,'descend');
A_big20 = A_ordered(1:20);

Does anyone know if this is possible in one line? If so, I would appreciate clues, ideas or an answer!

Robert Seifert
  • 25,078
  • 11
  • 68
  • 113
Fraukje
  • 673
  • 3
  • 20
  • 1
    I could suggest something like [this](http://stackoverflow.com/q/3627107/97160), but that would be pointless... Is it really that bad to write two lines of code instead of one! – Amro Jul 08 '14 at 10:07
  • Well not really of course, but this is something I actually encounter very often and for the sake of efficiency I was just genuinely curious if there exists a one-liner – Fraukje Jul 08 '14 at 10:15
  • 1
    ok fair enough :) For a really dirty hack, you could use the `ans` variable as in: `sort(x); ans(1:10)` (note how I didn't assign the output of `sort` to anything, hence `ans` got used). You see this sort of hacks a lot on [Cody](http://www.mathworks.com/matlabcentral/cody/) to cheat on solution size. – Amro Jul 08 '14 at 10:24

3 Answers3

5

you say you do this a lot, so the easiest and best way is to define a function on the MATLAB path:

function B = topN(A, n)

    if nargin==2 && n==0 
        B = []; return; end

    B = sort(A(:));
    if nargin>1 && n < numel(A)           
        B = B(1:n); end

end

and call your "one" liner:

top_ten = topN( randn(1,100), 10 );

If you want them to be in the original order (instead of sorted):

function B = topN_unsorted(A, n)

    if nargin>1 && n==0 
        B = []; return; end

    if nargin==1 || n > numel(A)
        B = A; 
    else
        [B,I] = sort(A(:));
        B = B(I(1:n));
    end

end
Rody Oldenhuis
  • 37,726
  • 7
  • 50
  • 96
4

For my opinion getfield is everything than "dirty" (though listed in the link by Amro). But he is right, it's slower than a simple two-line solution. If you insist for the sake of beauty, here we go:

A20 = getfield(sort(A,'descend'),{1:20})
Robert Seifert
  • 25,078
  • 11
  • 68
  • 113
  • but it is, check out the code: `edit getfield`. It basically receives its index arguments as `varargin` (a cell-array), then simply expands it using comma-separated list with `array(varargin{:})`. So to save on writing two lines of code, you executed many more plus the overhead of calling the function.. – Amro Jul 08 '14 at 10:33
  • @Amro I totally agree, but for the sake of beauty it is alright ;) – Robert Seifert Jul 08 '14 at 10:35
  • This was actually exactly what I was looking for (since this is useable for any kind of similar function operation), thanks for adding to my knowledge! – Fraukje Jul 08 '14 at 11:23
-1

You can use prctile:

a = randn(1,100);
n = 10;
topn = sort( a( a > prctile( a, 100 *( 1 - n/numel(a) ) ) ) )
Shai
  • 111,146
  • 38
  • 238
  • 371