6

まず、私のさびた Perl を許してください。Bugzilla の "whine.pl" を変更して、重大度でソートされたバグのリストを生成しようとしています。

したがって、ハッシュ参照の配列が得られます。各ハッシュには、特定のバグに関する一連の情報 (ID、担当者、重大度など) が含まれています。配列を重大度でソートしたい。これを行う最善の方法は何ですか?

いくつかの可能性を思いついた。1 つは、5 つの配列 (重大度のレベルごとに 1 つ) を作成し、配列をループして、ハッシュ参照を適切な重大度レベルの配列にプッシュすることです。この後、それらを再構築し、元の配列をソートされた配列に置き換えることができました。

私の友人が思いついた別の方法は、重大度レベル (ハッシュにテキストとして保存されている) をいくつかの数値に割り当て、それらを cmp することです。たぶん、このようなものですか?

sub getVal {
    my $entry = $_[0];
    %lookup = ( "critical" => 0, ... );
    return $lookup(entry("bug_severity"));
}
@sorted = sort { getVal($a) <=> getVal($b) } @unsorted;
4

4 に答える 4

7

getVal を必要以上に呼び出すのを避けるために、「decorate、sort、undecorate」を使用できます。装飾は、あなたが実際に気にかけている情報を取得しています。

my @decorated = map { [ $_, getVal($_) ] } @unsorted;

次に、装飾されたリストを並べ替えます。

my @sortedDecorate = sort { $a->[1] <=> $b->[1] } @decorated;

次に、元の情報を取得します (装飾を解除):

my @sorted = map { $_->[0] } @sortedDecorate;

または、それを行うためのよりPerlっぽい方法:

@sorted = map { $_->[0] }
          sort { $a->[1] <=> $b->[1] }
          map { [ $_, getVal($_) ] } @unsorted;
于 2009-10-28T22:13:53.433 に答える
4

シュワルツ変換を使用できます。

my @sorted = map  { $_->[1] }
             sort { $a->[0] <=> $b->[0] }
             map  { [ $lookup{$_->{bug_severity}, $_ ] } 
             @unsorted;

説明:

map  { [ $lookup{$_->{bug_severity}, $_ ] } @unsorted;

各バグを配列参照にマップします。配列参照の最初の要素は、ルックアップ テーブルからのバグの重大度の数値です。シュワルツ変換を使用すると、 のバグごとに 1 回だけ値を検索します@unsorted

それで、

sort { $a->[0] <=> $b->[0] }

その配列を最初の要素でソートします。ついに、

@sorted = map  { $_->[1] }

によって返された配列から元のバグを引き出しsortます。

getvalハッシュルックアップだけを行っている場合は、実際には必要ありません。

効率的なソーターを自動的に生成するには、CPAN モジュールSort::Makerが優れています。

use strict; use warnings;

use Sort::Maker;

my @bugs = (
    { name => 'bar', bug_severity => 'severe' },
    { name => 'baz', bug_severity => 'noncritical' },
    { name => 'foo', bug_severity => 'critical' },
);

my $sorter = make_sorter('ST',
    name      => 'severity_sorter',
    init_code => 'my %lookup = (
                     critical => 0,
                     severe => 1,
                     noncritical => -1 );',
    number    => [ code => '$lookup{$_->{bug_severity}}' ],
);

use Data::Dumper;
print Dumper $_ for severity_sorter( @bugs );

出力:

$VAR1 = {
          'name' => 'baz',
          'bug_severity' => '重大ではない'
        };
$VAR1 = {
          '名前' => 'フー',
          'bug_severity' => '重大'
        };
$VAR1 = {
          '名前' => 'バー',
          'bug_severity' => 'severe'
        };

naive メソッドを使用するときに必要なルックアップの数は、 の要素の数に依存することに注意してください@unsorted。簡単なプログラムを使用してそれらを数えることができます。

#!/usr/bin/perl

use strict;
use warnings;

my ($n_elements) = @ARGV;

my @keys = qw(a b c);
my %lookup = map { $keys[$_-1] => $_ } 1 .. @keys;

my @unsorted = map { $keys[rand 3] } 1 .. $n_elements;

my $n_lookups;

my @sorted = sort {
    $n_lookups += 2;
    $lookup{$a} <=> $lookup{$b}
} @unsorted;

print "It took $n_lookups lookups to sort $n_elements elements\n";

出力:

C:\Temp> tzt 10
10 個の要素をソートするのに 38 回のルックアップが必要でした

C:\Temp> tzt 100
100 個の要素をソートするのに 978 回のルックアップが必要でした

C:\Temp> tzt 1000
1000 個の要素をソートするのに 10916 回のルックアップが必要でした

C:\Temp> tzt 10000
10000 個の要素をソートするのに 113000 回のルックアップが必要でした

したがって、単純な並べ替えまたはシュワルツ変換の使用が適切な解決策であるかどうかを判断するには、より多くの情報が必要になります。

そして、これは@Etherの議論と一致しているように見える簡単なベンチマークです:

#!/usr/bin/perl

use strict;
use warnings;

use Benchmark qw( cmpthese );

my ($n_elements) = @ARGV;

my @keys = qw(foo bar baz);
my %lookup = map { $keys[$_] => $_ } 0 .. $#keys;

my @unsorted = map { {v => $keys[rand 3]} } 1 .. $n_elements;

cmpthese(-1, {
    naive => sub {
        my @sorted = sort {
            $lookup{$a->{v}} <=> $lookup{$b->{v}}
        } @unsorted;
    },
    schwartzian => sub {
        my @sorted = map  { $_->[1] }
                     sort { $a->[0] <=> $b->[0] }
                     map  { [$lookup{$_->{v}}, $_] }
                     @unsorted;
    }
});

出力:

C:\Temp> tzt 10
               シュワルツのナイーブを評価する
schwartzian 18842/s -- -29%
ナイーブ 26357/s 40% --

C:\Temp> tzt 100
              ナイーブ・シュワルツィアンを評価する
ナイーブ 1365/s -- -11%
schwartzian 1532/s 12% --

C:\Temp> tzt 1000
             ナイーブ・シュワルツィアンを評価する
ナイーブ 121/s -- -11%
schwartzian 135/s 12% --
于 2009-10-28T22:15:11.463 に答える
3

私はあなたの提案された解決策が好きです:

my %sevs = (critical => 0, high => 1, ...);
my @sorted = sort { $sevs{$a->{bug_severity}} <=> $sevs{$b->{bug_severity}} } @unsorted
于 2009-10-28T22:09:57.730 に答える
0

次のように、ルックアップ テーブルを使用して bugzilla 重大度の順序を決定できます (サンプル データを使用して説明します)。

use strict; use warnings;
use Data::Dumper;

my @bugInfo = (
                { id => 1,
                  assignee => 'Bob',
                  severity => 'HIGH'
                },
                { id => 2,
                  assignee => 'Anna',
                  severity => 'LOW'
                },
                { id => 3,
                  assignee => 'Carl',
                  severity => 'EXTREME'
                },
              );
my %severity_ordering = (
    EXTREME => 0,
    HIGH => 1,
    MEDIUM => 2,
    LOW => 3,
);
sub byseverity
{
    $severity_ordering{$a->{severity}} <=> $severity_ordering{$b->{severity}}
}

my @sortedBugs = sort byseverity @bugInfo;
print Dumper(\@sortedBugs);

収量:

$VAR1 = [
          {
            'assignee' => 'Carl',
            'id' => 3,
            'severity' => 'EXTREME'
          },
          {
            'assignee' => 'Bob',
            'id' => 1,
            'severity' => 'HIGH'
          },
          {
            'assignee' => 'Anna',
            'id' => 2,
            'severity' => 'LOW'
          }
        ];
于 2009-10-28T22:25:35.623 に答える