新規記事投稿 フォロー記事投稿 記事のキャンセル
From: にあ <nir@mxa.meshnet.or.jp>
Subject: Re: [Q] perl での 二つ以上のキーを用いたソート
Date: 1998/08/07 07:50:32
Reference: mesh.program/00528

8月6日に、素人でGO!さんは書きました。

>確かにそんなことが書いてありました。
>そこで素人の質問になるわけですが…配列の中に名前を付けるにはどうすればいいのでしょうか?
>
えーと、先の例はperl4でも使えるように、多次元配列は使わずに、個々の比較項目を
別個に連想記憶に入れてからソートするものでしたので、例えば、

#!/usr/local/bin/perl4

while (<DATA>) {
        chop;
        ($date, $tasty, $cheap, $cute, $key) = split(/,\s*/);
        push(@shop, $key);
        $date{$key} = $date;
        $tasty{$key} = $tasty;
        $cheap{$key} = $cheap;
        $cute{$key} = $cute;
}

@sorted = sort good @shop;

foreach $key (@sorted) {
        printf("%s, (%s, %s, %s), %s\n",
                $date{$key}, $tasty{$key}, $cheap{$key}, $cute{$key}, $key);
}

exit(0);

sub good {
        $tasty{$a} cmp $tasty{$b}
                ||
        $cheap{$a} cmp $cheap{$b}
                ||
        $cute{$a} cmp $cute{$b}
                ||
        $a cmp $b;
}

__END__
1998/04/23, D, B, E, 三茶のA
1998/05/10, B, C, A, 広尾のB
1998/05/11, C, A, B, 表参道のA
1998/06/26, B, A, C, 用賀のC
1998/07/05, D, B, A, 外苑前のA

とかなっていると、出力は、

1998/06/26, (B, A, C), 用賀のC
1998/05/10, (B, C, A), 広尾のB
1998/05/11, (C, A, B), 表参道のA
1998/07/05, (D, B, A), 外苑前のA
1998/04/23, (D, B, E), 三茶のA

とかになるわけです。

>@店 の中に 5つ(見つけた日付、おいしさ、安さ、かわいさ、場所)項目があったとします。
>そんな場合にこういうソートをするとき、どのように指定すればいいんでしょうか。
> 
perl5での多次元配列(まがい)を使ってデータを入れてるとすると、配列の添字で指定した方が
やりやすいでしょうね。例えば、

#!/usr/local/bin/perl5

$tasty = 1;
$cheap = 2;
$cute  = 3;

while (<DATA>) {
        chop;
        push(@shop, [split(/,\s*/)]);
}

@sorted = sort good @shop;

foreach $shop (@sorted) {
        printf("%s, (%s, %s, %s), %s\n", @$shop);
}

exit(0);

sub good {
        $$a[$tasty] cmp $$b[$tasty]
                ||
        $$a[$cheap] cmp $$b[$cheap]
                ||
        $$a[$cute] cmp $$b[$cute]
                ||
        $a cmp $b;
}

__END__
1998/04/23, D, B, E, 三茶のA
1998/05/10, B, C, A, 広尾のB
1998/05/11, C, A, B, 表参道のA
1998/06/26, B, A, C, 用賀のC
1998/07/05, D, B, A, 外苑前のA

でも同じ出力になりますね。
多次元配列では無くて、ハッシュの配列を使えば、

#!/usr/local/bin/perl5

while (<DATA>) {
        chop;
        ($date, $tasty, $cheap, $cute, $key) = split(/,\s*/);
        $shop = {date  => $date,
                 tasty => $tasty,
                 cheap => $cheap,
                 cute  => $cute,
                 key   => $key};
        push(@shop, $shop);
}

@sorted = sort good @shop;

foreach $shop (@sorted) {
        printf("%s, (%s, %s, %s), %s\n",
                $shop->{date}, $shop->{tasty}, $shop->{cheap}, $shop->{cute}, $shop->{key});
}

exit(0);

sub good {
        $a->{tasty} cmp $b->{tasty}
                ||
        $a->{cheap} cmp $b->{cheap}
                ||
        $a->{cute} cmp $b->{cute}
                ||
        $a->{key} cmp $b->{key};
}

__END__
1998/04/23, D, B, E, 三茶のA
1998/05/10, B, C, A, 広尾のB
1998/05/11, C, A, B, 表参道のA
1998/06/26, B, A, C, 用賀のC
1998/07/05, D, B, A, 外苑前のA

な感じになりますか。もちろん出力は同じです。