简体   繁体   中英

How to sort this custom hashes of hashes in perl on the value

I am facing an issue with the sort functionality on my Application. I need to sort my Hash of hashes on the lname key under the instructors . The legacy application is written in Perl.

Here is the dump of the Hash which i need to sort.

$VAR1 = {
      'instructors' => [
                         {
                           'is_placeholder' => 0,
                           'lname' => 'Lordy',
                           'name' => 'Daniel Lordy'
                         },
                         {
                           'is_placeholder' => 0,
                           'lname' => 'Fisher',
                           'name' => 'Bethy Fisher'
                         },
                         {
                           'is_placeholder' => 0,
                           'lname' => 'Jaya',
                           'name' => 'Jennifer Jaya'
                         },
                       ],
      'id' => '1237058',
      'XXX' => {
                  'name' => 'Fall 2015 MFT Master 695',
                },
      'YYY' => '45'
    };

The instructors key in the above structure can be empty as well. For Example:

$VAR1 = {
      'instructors' => [],
      'id' => '1237058',
      'XXX' => {
                  'name' => 'Fall 2015 MFT Master 695',
                },
      'YYY' => '45'
    };

In my application, Users have an option to sort the column based on instructor names. So when user sorts by ascending order, the application should show rows which have instructors are empty at the start and then show the rest of the rows in which each row has the instructor names sorted in ascending order. Vice versa for Descending Order.

This is the code which I have tried until now.

if( $sort_order eq 'ASC' ) {
  foreach my $elem ( @$course_sections ) {
    my @sorted = map { $_->[1] }
                  sort { $a->[0] cmp $b->[0] }
                    map { [$_->{'lname'}, $_] } @{$elem->{'instructors'}};

}
if( $sort_order eq 'DESC' ) {
  foreach my $elem ( @$course_sections ) {
    my @sorted = map { $_->[1] }
                  sort { $b->[0] cmp $a->[0] }
                    map { [$_->{'lname'}, $_] } @{$elem->{'instructors'}};

}

How do I get this @sorted hash affect the order of rows in @$course_sections . Let me know if there is any easier way to do it.

Thanks in Advance.

You need to replace each instructors array ref with the sorted version that you created in your foreach loop. That way you get the instructors of each individual row sorted. Then you can sort the whole $course_sections by the name of the first instructor of each row.

# sort the instructors in-place
foreach my $elem (@$course_sections) {
    $elem->{'instructors'} = [
        map  { $_->[1] }
        sort { $a->[0] cmp $b->[0] }
        map  { [ $_->{'lname'}, $_ ] } @{ $elem->{'instructors'} }
    ];
}

# sort the courses by first instructor
$course_sections = [
    map      { $_->[1] }
        sort { $a->[0] cmp $b->[0] }
        map  { [ ( $_->{'instructors'}->[0] ? $_->{'instructors'}->[0]->{'lname'} : q{} ), $_ ] }
        @$course_sections
];

Make sure to replace undef values with empty strings so the cmp doesn't blow up. We shouldn't do $_->{'instructors'}->[0]->{'lname'} // q{} because autovivification might create a bunch of empty stuff in our data structure.

Here's your example data pulled together:

my $course_sections = [
    {
        'instructors' => [
            {
                'is_placeholder' => 0,
                'lname'          => 'Lordy',
                'name'           => 'Daniel Lordy'
            },
            {
                'is_placeholder' => 0,
                'lname'          => 'Fisher',
                'name'           => 'Bethy Fisher'
            },
            {
                'is_placeholder' => 0,
                'lname'          => 'Jaya',
                'name'           => 'Jennifer Jaya'
            },
        ],
        'id'  => '1237058',
        'XXX' => {
            'name' => 'Fall 2015 MFT Master 695',
        },
        'YYY' => '45'
    },
    {
        'instructors' => [],
        'id'          => '1237058',
        'XXX'         => {
            'name' => 'Fall 2015 MFT Master 695',
        },
        'YYY' => '45'
    }
];

And this is the output, dumped with Data::Printer.

\ [
    [0] {
        id            1237058,
        instructors   [],
        XXX           {
            name   "Fall 2015 MFT Master 695"
        },
        YYY           45
    },
    [1] {
        id            1237058,
        instructors   [
            [0] {
                is_placeholder   0,
                lname            "Fisher",
                name             "Bethy Fisher"
            },
            [1] {
                is_placeholder   0,
                lname            "Jaya",
                name             "Jennifer Jaya"
            },
            [2] {
                is_placeholder   0,
                lname            "Lordy",
                name             "Daniel Lordy"
            }
        ],
        XXX           {
            name   "Fall 2015 MFT Master 695"
        },
        YYY           45
    }
]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM