51220


例えば（[1,'A'],[2,'B'],.....,[10,'X'])のとき、'X'を取り出すには、どうしたらいいでしょうか？  
forループでごりごりやればできますが、map、grep、maxのような関数を使ってエレガントに記述したいのですが。


CC BY-SA 4.0
2018-11-11T01:27:08.467
50190
2018-12-14T14:06:06.260
24431
question
array perl
perlにて、2つの要素からなる配列のリファレンスの配列から、0番目の要素の値が最大の1番目の要素を取得したい。


自己回答ですが、List::Util のreduceを使って、

[code]

     (reduce { $a->[0]>$b->[0] ? $a : $b } @arr)->[1];
    
[/code]

と書けます。  
metropolisさんのコメントを参考にさせていただきました。


CC BY-SA 4.0
2018-11-11T12:02:08.647
50210
2018-11-11T12:02:08.647
24431
50190
answer


Non-COREなCPANモジュールを使えるのなら `List::UtilsBy` の`max_by`がそのものずばりです。

[code]

    #!/usr/bin/perl
    use strict;
    use warnings;
    use List::UtilsBy qw(max_by);
    
    my @arr = (
        [1, 'A'],
        [2, 'B'],
        [3, 'C'],
        [4, 'D'],
        [5, 'E'],
        [10, 'X'],
    );
    
    my $max = max_by { $_->[0] } @arr;
    print $max->[1];
    
[/code]

List::UtilsByの利点はmaxとなる要素が複数ある場合にも対応できることです。

[code]

    my @arr = (
        [1, 'A'],
        [2, 'B'],
        [3, 'C'],
        [4, 'D'],
        [5, 'E'],
        [10, 'X'],
        [10, 'Z'],
    );
    
    my @max = max_by { $_->[0] } @arr;
    
    use Data::Dumper;
    print Dumper @max;
    __END__
    $VAR1 = [
              10,
              'X'
            ];
    $VAR2 = [
              10,
              'Z'
            ];
    
[/code]

`max_by` 自体は実装も簡潔なので、COREモジュールが使えない場合サブルーチンだけ拝借してもいいかもしれません。

[code]

    #!/usr/bin/perl
    use strict;
    use warnings;
    
    BEGIN {
        # Borrowed from List::UtilsBy@0.11
        sub max_by(&@)
        {
           my $code = shift;
    
           return unless @_;
    
           local $_;
    
           my @maximal = $_ = shift @_;
           my $max     = $code->( $_ );
    
           foreach ( @_ ) {
              my $this = $code->( $_ );
              if( $this > $max ) {
                 @maximal = $_;
                 $max     = $this;
              }
              elsif( wantarray and $this == $max ) {
                 push @maximal, $_;
              }
           }
    
           return wantarray ? @maximal : $maximal[0];
        }
    }
    
    my @arr = (
        [1, 'A'],
        [2, 'B'],
        [3, 'C'],
        [4, 'D'],
        [5, 'E'],
        [10, 'X'],
    );
    
    my $max = max_by { $_->[0] } @arr;
    print $max->[1];
    
[/code]


CC BY-SA 4.0
2018-12-14T14:06:06.260
51220
2018-12-14T14:06:06.260
62
50190
answer