perlのsort関数はかなり優秀で、下記の様に簡単に複数条件での並び替えが可能です。
@data = sort{ $a->{'key1'} <=> $b->{'key1'} || $a->{'str1'} cmp $b->{'str1'} } @data
が、しかし、置換(eオプション)の様に変数展開ができません。
my $e = "$a->{'key1'} <=> $b->{'key1'} || $a->{'str1'} cmp $b->{'str1'}";
@data = sort{ $e } @data
※みたいなことはできなかったです
evalを使用することで、課題クリアです!
my @data = (
{ 'name' => 'okuno',
'key' => '1',
'key2' => '1',
},
{ 'name' => 'yamada',
'key' => '2',
'key2' => '2',
},
{ 'name' => 'hanaoka',
'key' => '1',
'key2' => '3',
},
{ 'name' => 'suzuki',
'key' => '1',
'key2' => '2',
},
);
my @keys = ('key_number','key2_number'); # _numberで数値検索の判定
eval "\@data = sort { @{[&get_sort_formula(@keys)]} } \@data";
# @dataがsortされるので、後は必要な処理をどうぞ
exit;
# sort式リターン exp) $a->{'key'} <=> $b->{'key'} || $a->{'key2'} <=> $b->{'key2'}
sub get_sort_formula {
my @keys = @_;
my @sort;
for my $order (@keys) {
my ( $f, $a_d ) = split( / /, $order );
my (@f) = split( /_/, $f ); # 数値 or 文字列判定 key_number
if ($a_d) {
if ( $f[1] ) {
push( @sort, "\$b->{'$f[0]'} <=> \$a->{'$f[0]'}");
}
else {
push( @sort, "\$b->{'$f[0]'} cmp \$a->{'$f[0]'}");
}
}
else {
if ( $f[1] ) {
push( @sort, "\$a->{'$f[0]'} <=> \$b->{'$f[0]'}");
}
else {
push( @sort, "\$a->{'$f[0]'} cmp \$b->{'$f[0]'}");
}
}
}
return join( ' || ', @sort);
}
eval実行式に文字列や変数だと実行されなかったり展開されたりするので、ダブルクォーテーションと¥を駆使することが重要です👍(evalを使用する時は変数エスケープなど慎重に)