perl

Sorting an array of hashes by multiple keys in Perl


I have an array reference containing hashes (i.e., @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'
              }
];

I want to sort it on the basis of all three keys (i.e., brand, supplier and PO). The order of sorting should be brand first, then supplier and then finally on PO.

The array reference after sorting should be:

$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'
              },
];

Solution

  • Since <=> and cmp return 0 to indicate equality, and that's false, and because Perl's logical Boolean operators return the deciding value instead of just 0 or 1, sorting by multiple keys is as easy as stringing multiple comparisons together with or or ||:

    @$arr_ref = sort { $a->{brand}    cmp $b->{brand}    or 
                       $a->{supplier} cmp $b->{supplier} or 
                       $a->{PO}       <=> $b->{PO} 
                     } @$arr_ref;
    

    I'm assuming that PO is a numeric field, so you use <=> for it instead of cmp.