ソート&順位付け 

なぜか立ち止まって、周囲を見回すような場所がある。

-- Perl Scripts --

  1. テスト用スクリプト
  2. サブルーチン
  3. 使い方
---------------------------------

トップページへ




0.  最初に 

自分の場合これらについては、いい加減にやっているけどケッコウこれで
悩んでいるヒトもいるようだ。

質問があったので、ついでに少し考えてみた。
これなら少しの修正で、汎用としても使えるかもしれない。
これは競馬データを扱うときに避けて通れない。ということで、




1.  テスト用スクリプト  

以下は実際に使ったテストスクリプト。testsort.pl
説明用と出力時のコメントを追加したので、参考に

#!/usr/bin/perl
# $Id: $
# testsort.pl
#==========================================================================#
use strict ;
my @hr ;    # 配列
my $ub ;    # 馬番
my $su ;    # 数値
# ある馬番の数値を取り出すときは、$hr[$ub]
# つまり、$hr[$ub] = $su の形。etc. $hr[3] = 6 ;
# 例えば、12頭のデータとして以下があったとする。
# 一応最初の項は、お約束で $hr[0] 。
# @hr = ( '', 5, 10, 6, 8, 9, 7, 0, 10, 8, 3, 5, 4 ) ;
# あるいは
@hr[ 1..12 ] =  ( 5, 10, 6, 8, 9, 7, 0, 10, 8, 3, 5, 4 ) ;
# この数値で順序付けしたいことがある。
# そのまま昇順でソートすると
my @new = sort { $a <=> $b } @hr ;

print join ',', @hr ;   # 元の配列
print "\n" ;
print join ',', @new ;  # ソートされた配列
print "\n" ;

# H:\Test>testsort.pl
# ,5,10,6,8,9,7,0,10,8,3,5,4
# ,0,3,4,5,5,6,7,8,8,9,10,10

# 順序付けに 0 は必要ないときは外す
# grep { $_ > 0 } と同じ結果
my @grepnew = grep { $_ } @hr ;

print join ',', @grepnew ;
print "\n" ;
# 5,10,6,8,9,7,10,8,3,5,4

# -------------------------------------------
# ということで、複合形で以下のように書ける

my @sorted = sort { $a <=> $b }
             grep { $_ } @hr ;

print join ',', @sorted ;
print "\n" ;
# 3,4,5,5,6,7,8,8,9,10,10

# 一応、順序どおりに並んだ。# 折角ここまで分かったのなら、
# $jun[$ub] で馬番ごとに順位を出したい。
# ハッシュ( %kj )にその数値が何番目かをメモさせる。
# etc. $kj{ '5' } = 3 
my $i ;
my @jun ;
my %kj ;
my $num = 1 ;
my $non = 0 ;       # 存在しないはずの数値をセット
for $i ( @sorted ) {
    if ( $i != $non ) {
        $kj{$i} = $num ;
        $non = $i ;
    }
    $num++ ;
}
# 最初の配列と比較しながら、@jun という配列を作る。
for $i ( 1..$#hr ) {
    next if $hr[$i] == 0 ;
    $jun[$i] = $kj{ $hr[$i] } ;
}
print  join ',', @jun ;
print "\n" ;
# ,3,10,5,7,9,6,,10,7,1,3,2

# これで、例えば馬番 9 が何番目の数値を持っているかがワカル
print $jun[9], "番目だ\n" ;
# 7番目だ

__END__

数値は 0 から、というのがプログラム言語。配列は 0 が起点。
存在しないものは数えたくないのが人間。指折って数えるときも 1、2、3。
他は、応用問題。もっとうまい書き方がキットある。




2.  サブルーチン  


sub sort_sj {   # 昇順ソート順位
    my @hr = @_ ;           # 引数は配列
    # 降順の場合は、sort { $b <=> $a } 
    # grep で順位の対象を限定
    my @sorted = sort { $a <=> $b }
                 grep { $_ > 0 } @hr ;
    my $i ;
    my @jun ;
    my %kj ;
    my $num = 1 ;
    my $non = 0 ;       # 存在しないはずの数値をセット
    for $i ( @sorted ) {
        if ( $i != $non ) {
            $kj{$i} = $num ;
            $non = $i ;
        }
        $num++ ;
    }
    # 最初の配列と比較しながら、@jun という配列を作る。
    for $i ( 1..$#hr ) {
        next if $hr[$i] == 0 ;
        $jun[$i] = $kj{ $hr[$i] } ;
    }
    return @jun ;			# 戻り値も配列
}

リファレンスを使うほうが楽かもしれないが、




3.  使い方  


このサブルーチンは、引数として一つの配列をとり、処理後の配列として返す。
例えば、各馬の3Fタイム( 1/10秒 )の場合、
[1] 348
[2] 342
[3] 343
[4] 338
[5] 361
[6] 354
[7] 349
[8] 350
[9] 348
これを配列で表現すると、
my @hrr ;
@hrr[ 1..9 ] = ( 348, 342, 343, 338, 361, 354, 349, 350, 348 ) ;

つまり、馬番[4] のタイムは 338 ということで、
$hrr[4] = 338 ;

順序付けした結果の配列名を @junn とすると、

my @junn = &sort_sj( @hrr ) ;

結果、
@junn = ( '', 4, 2, 3, 1, 9, 8, 6, 7, 4 ) ;
つまり
$junn[1] = 4 ;
$junn[2] = 2 ;
$junn[3] = 3 ;
以下略。




戻る トップページへ