txt: ## dist_cpan-UZLUISF-Ranker.md
  # NAME
  
  Ranker - a module to rank a list of elements.
  
  # DESCRIPTION
  
  This is a module for ranking a list/array of scorable elements using various ranking strategies written in Raku.
  
  It's mostly based on [Ilya Scharrenbroich's Ruby library](https://github.com/quidproquo/ranker) by the same name.
  
  # INSTALLATION
  
  Either:
  
  * from CPAN:
  
    * `zef install Ranker`
  * from local directory:
  
    * `git clone git@gitlab.com:uzluisf/ranker.git` or [download it](https://gitlab.com/uzluisf/ranker)
    * `zef install path/to/ranker/`
  
  # SYNOPSIS
  
  ## Default Ranking
  
  Default ranking will assume values are numeric and rank them in their descending order. For example, a score of 100 is higher than a score of 50 and thus appears before as in `[100, 50]`.
  
  ```
  use Ranker;
  
  my @scores = 1, 1, 2, 3, 3, 1, 4, 4, 5, 6, 8, 1, 0, 8;
  
  my $rankings = Ranker::rank(@scores);
  put $rankings.elems; #=> 8
  
  my $ranking = $rankings[0];
  given $ranking {
      .rank       .put; #=> 1
      .score      .put; #=> 8
      .rankables  .put; #=> [8, 8]
      .percentile .put; #=> 100
      .z-score    .put; #=> 1.83921346366645
  }
  
  ```
  
  ## Custom Ranking by Block
  
  Custom ranking allows for ranking of objects by using an anonymous subroutine which can created with `sub`, with a pointy block or with a block.
  
  ```
  class Player {
      has Int $.score;
  }
  
  my @players = (0, 100, 1000, 25).map: Player.new(score => *);
  my (&score, $rankings);
  
  # Explicit:
  &score = -> $player { $player.score };
  $rankings = Ranker::rank(@players, by => &score);
  
  # Still more explicit:
  &score = sub( Player:D $player ) { $player.score };
  $rankings = Ranker::rank(@players, by => &score);
  
  # Same thing but more succint: 
  $rankings = Ranker::rank(@players, by => { $^player.score });
  
  ```
  
  In some cases, objects need to be ranked by score in ascending order. For instance, if you were ranking golf players. In this case, 75 is higher than a score of 100 and thus appears before as in `[75, 100]`.
  
  ```
  class GolfPlayer is Player { }
  
  my @golfplayers = (72, 100, 138, 54).map: GolfPlayer.new(score => *);
  my $rankings = Ranker::rank(
      @golfplayers,              # Rankable values
      by => -> gp { $gp.score }, # Block to rank by
      :asc                       # Use ascending order
  );
  
  ```
  
  ## Ranking Strategies
  
  Ranker provides several ranking strategies, which are mostly based on the Wikipedia entry for [ranking](http://en.wikipedia.org/wiki/Ranking). Strategies can be passed in as an option to the `Ranker::rank` subroutine.
  
  ```
  my $rankings = Ranker::rank(
      @players,
      by       => { $^p.score },
      strategy => 'ordinal',
  );
  
  ```
  
  The possible string values for the default strategies are: `'standard'`, `'modified'`, `'ordinal'`, `'dense'`, and `'fractional'`.
  
  ### **Standard Competition Ranking ("1224" ranking)**
  
  This is the default ranking strategy used by `Ranker`. For more info, see the Wikipedia entry on [Standard Competition Ranking](https://en.wikipedia.org/wiki/Ranking#Standard_competition_ranking_(%221224%22_ranking)).
  
  ```
  my $rankings = Ranker::rank(
      @players,
      by       => { $^p.score },
      strategy => 'standard',
  );
  
  ```
  
  ### **Modified Competition Ranking ("1334" ranking)**
  
  For more info, see the Wikipedia entry on [Modified Competition Ranking](https://en.wikipedia.org/wiki/Ranking#Modified_competition_ranking_(%221334%22_ranking)).
  
  ```
  my $rankings = Ranker::rank(
      @players,
      by       => { $^p.score },
      strategy => 'modified',
  );
  
  ```
  
  ### **Dense Ranking ("1223" ranking)**
  
  For more info, see the Wikipedia entry on [Dense Ranking](https://en.wikipedia.org/wiki/Ranking#Dense_ranking_(%221223%22_ranking))
  
  ```
  my $rankings = Ranker::rank(
      @players,
      by       => { $^p.score },
      strategy => 'dense',
  );
  
  ```
  
  ### **Ordinal Ranking ("1234" ranking)**
  
  For more info, see the Wikipedia entry on [Ordinal Ranking](https://en.wikipedia.org/wiki/Ranking#Ordinal_ranking_(%221234%22_ranking)).
  
  ```
  my $rankings = Ranker::rank(
      @players,
      by       => { $^p.score },
      strategy => 'ordinal',
  );
  
  ```
  
  ### **Fractional Ranking ("1 2.5 2.5 4" ranking)**
  
  For more info, see the Wikipedia entry on [Fractional Ranking](https://en.wikipedia.org/wiki/Ranking#Fractional_ranking_(%221_2.5_2.5_4%22_ranking)).
  
  ```
  my $rankings = Ranker::rank(
      @players,
      by       => { $^p.score },
      strategy => 'fractional',
  );
  
  ```
  
  ## Custom Strategies
  
  `Ranker` allows you to write your own strategies and supply them to the `Ranker::rank` subroutine. To do this, you must compose the `Strategy` role into a class and use [`::()`](https://docs.perl6.org/language/packages#Interpolating_into_names) to interpolate the class name into a package or variable name. `Strategy` is the role from which the default «Strategy» classes are composed.
  
  ```
  use Ranker;
  use Ranker::Strategies;
  
  # Composing Strategy into a class
  class MyCustomStrategy does Strategy {
  
    method execute {
      # You must implement this method ;-)
    }
  
  }
  
  my $rankings = Ranker::rank(
      @players,
      by       => -> $p { $p.score },
      strategy => ::('MyCustomStrategy') # Passing the package-interpolated class name
  );
  
  ```
  
  By default, only the `Strategy` role is exported with `use Ranker::Strategies`, which must be composed before it's used. To export a default strategy, you must specify it with a `use` statement. For instance, `use Ranker::Strategies :dense` exports `Strategies::Dense` which can then be instantiated:
  
  ```
  use Ranker::Strategies :dense;
  
  my @scores = 44, 42, 42, 43;
  my $ds = Dense.new: rankables => @scores, options => { :asc };
  
  ```
  
  # ROUTINES
  
  ### `Ranker`
  
  * `Ranker::rank(@rankables, *%options)`
  
    * `@rankables` - list of elements to be ranked
    * `%options` - key-value pairs to specify a custom ranking with `by` (e.g., `by => { $^value }`), a sorting order with `asc` (e.g., `asc => True`) and strategy to be used with `strategy` (e.g., `strategy => 'dense'`).
  
  By default, values are assumed to be numeric and ranked in descending order using the standard-competition ranking strategy. Thus, the following two calls achieve the same thing:
  
  * `Ranker::rank(@values);`
  * `Ranker::rank(@values, :by({ $^value }), :asc(False), :strategy('standard'));`
  
  ### Others
  
  Run `p6doc` on `Ranker::Ranking`, `Ranker::Rankings` and `Ranker::Strategies` to get the methods made available by `Ranking`, `Rankings` and `Strategy` respectively.
  
  # AUTHOR
  
  Luis F. Uceta
  
  # LICENSE
  
  Artistic License 2.0
  