按多个键对哈希数组进行排序的Perl方法

24

我有一个包含哈希引用的数组(即@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)进行排序。 排序的顺序应该是先品牌,然后供应商,最后是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'       
              },
];
3个回答

56

由于 <=>cmp 返回0表示相等,而0是假的,且因为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


1
只是增加一个有趣的情景案例。我不得不将 sort {...} 的返回值分配给一个新数组,而不是使用旧数组 (@$arr_ref)。前者返回了空引用...仍然不确定为什么。谢谢。 - mhz

6
以下代码将对数组引用进行排序并将数组放回到$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}
}

2
您可以使用 Sort::Key 中附带的 Multi,在这种情况下,我们正在使用 ssikeysort,它期望一个返回字符串、字符串和整数的块,并按该元组对值进行排序。(ssi 中的 s 代表字符串,i 代表整数。)
use Sort::Key::Multi qw(ssikeysort);

@$arr_ref = ssikeysort { $_->{brand}, $_->{supplier}, $_->{PO} } @$arr_ref;

你也可以使用就地变更的变体,这种方法使用的内存更少:
use Sort::Key::Multi qw(ssikeysort_inplace);

ssikeysort_inplace { $_->{brand}, $_->{supplier}, $_->{PO} } @$arr_ref;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接