Сортировка массива хэша несколькими ключами Perl
У меня есть ссылка массива, содержащая хеши (т.е. @AOH)
$arr_ref = [ { 'brand' => 'A',
'supplier' => 'X',
'PO' => '2'
},
{ 'brand' => 'B',
'supplier' => 'Y',
'PO' => '1'
},
{ 'brand' => 'B',
'supplier' => 'X',
'PO' => '2'
},
{ 'brand' => 'A',
'supplier' => 'X',
'PO' => '1'
},
{ 'brand' => 'B',
'supplier' => 'X',
'PO' => '1'
}
];
Я хочу сортировать его на основе всех трех клавиш (т.е. бренда, поставщика и ПО).
Порядок сортировки должен быть брендом первым, затем поставщиком, а затем, наконец, PO.
Реферация массива после сортировки должна быть:
$arr_ref = [ { 'brand' => 'A',
'supplier' => 'X',
'PO' => '1'
},
{ 'brand' => 'A',
'supplier' => 'X',
'PO' => '2'
},
{ 'brand' => 'B',
'supplier' => 'X',
'PO' => '1'
},
{ 'brand' => 'B',
'supplier' => 'X',
'PO' => '2'
},
{ 'brand' => 'B',
'supplier' => 'Y',
'PO' => '1'
},
];
Ответы
Ответ 1
Так как <=>
и cmp
возвращает 0, чтобы указать равенство, а это false, и поскольку логические логические операторы Perl возвращают решающее значение вместо 0 или 1 сортировка по нескольким клавишам так же просто, как наложение нескольких сравнений вместе с or
или ||
:
@$arr_ref = sort { $a->{brand} cmp $b->{brand} or
$a->{supplier} cmp $b->{supplier} or
$a->{PO} <=> $b->{PO}
} @$arr_ref;
Я предполагаю, что PO - числовое поле, поэтому вместо cmp
вы используете <=>
.
Ответ 2
Следующее должно отсортировать ссылку на массив и поместить массив обратно в $arr_ref
:
$arr_ref = [sort by_brand_supplier_PO @$arr_ref];
sub by_brand_supplier_PO {
$a->{brand} cmp $b->{brand} ||
$a->{supplier} cmp $b->{supplier} ||
$a->{PO} <=> $b->{PO}
}
Ответ 3
Вы можете использовать Sort::Key::Multi, распространяемый с помощью Sort:: Key.
В этом случае мы используем ssikeysort
, который ожидает блок, который возвращает строку, строку и целое число и сортирует значения по этому кортежу. (s
в ssi
обозначает строку и i
для целого числа.)
use Sort::Key::Multi qw(ssikeysort);
@$arr_ref = ssikeysort { $_->{brand}, $_->{supplier}, $_->{PO} } @$arr_ref;
Вы также можете использовать вариант in-place, который использует меньше памяти:
use Sort::Key::Multi qw(ssikeysort_inplace);
ssikeysort_inplace { $_->{brand}, $_->{supplier}, $_->{PO} } @$arr_ref;