skip to Main Content

I have a bigger multidimensional hash which consist of hashes and array within it, I’m able to get the array of hashes out of that which is only useful of the entire larger hash, now I’m trying to print a specific element or values of a key.

Original Hash

{
      "grade1": {
        "sections": {
          "groups": "group-a"
        }
      },
      "grade2": {
        "sections": {
          "groups": "group-b"
        }
      },
      "grade3": {
        "departments": [
          {
            "allowedsubjects": "ngeneralnmathnphysicsnchemistry",
            "name": "class1",
            "multiple": false,
            "description": "",
            "required": "optional"
          },
          {
            "allowedsubjects": "ngeneralnbiologynphysicsnchemistry",
            "name": "class2",
            "multiple": false,
            "description": "",
            "required": "optional"
          }
        ]
      }
    }

My Script

#!/usr/bin/perl
use Cpanel::JSON::XS;
use strict;
use v5.16.3;
use Data::Dumper;

my $json_text ='{ "grade1": { "sections": { "groups": "group-a" } }, "grade2": { "sections": { "groups": "group-b" } }, "grade3": { "departments": [ { "allowedsubjects": "ngeneralnmathnphysicsnchemistry", "name": "class2", "multiple": false, "description": "", "required": "optional" }, { "allowedsubjects": "ngeneralnbiologynphysicsnchemistry", "name": "class1", "multiple": false, "description": "", "required": "optional" } ] } }';

my $json_obj = decode_json($json_text);

#print Dumper $json_obj;
my %school = %{$json_obj};
## Half working
    my @AoH = @{$school{"grade3"}{"departments"}};
    my @lines;
    for my $href ( @AoH ) {
        for my $key ( keys %$href ) {
          push @lines, $href->{$key};
         }
    }
print @lines;

Output

0optionalclass2
general
math
physics
chemistryoptionalclass1
general
biology
physics
chemistry0

How can I print just the values of allowedsubjects based on class1 or class2 as criteria.

Expected Out put if class1 is selected

general
math
physics
chemistry

2

Answers


  1. Let’s start by avoiding needless copies of hashes and arrays. We’re also going to use better variable names than AoH, href and key.

    my $school = decode_json($json);
    my $depts = $school->{grade3}{departments};
    

    Now we want the departments that have the value of $dept_name for name. grep is a good tool for filtering.

    my $dept_name = 'class1';
    my @matching_depts = grep { $_->{name} eq $dept_name } @$depts;
    

    Then, it’s just a question of iterating over the matching departments, and printing the desired values.

    for my $dept (@matching_depts) {
       say $dept->{allowedsubjects};
    }
    

    Except not quite. That prints

                     <-- Blank line
    general
    biology
    physics
    chemistry
    

    Fix:

    for my $dept (@matching_depts) {
       say substr($dept->{allowedsubjects}, 1);
    }
    

    Alternative fix:

    for my $dept (@matching_depts) {
       my @subjects = grep { $_ ne "" } split /n/, $dept->{allowedsubjects};
       for my $subject (@subjects) {
          say $subject;
       }
    }
    
    Login or Signup to reply.
  2. You can simplify quite a bit in your code. It boils down to this loop.

    for my $department ( @{ $school->{grade3}{departments} } ) {
        if ($department->{name} eq 'class1') {
            print $department->{allowedsubjects};
        }
    }
    

    I’ve dropped your @lines as there is no need to store the output for this example. I’ve also removed @AoH, as we can access that directly. I’ve renamed $href to $department, which is more descriptive.

    It then boils down to looking at the specific name key inside each department, comparing with the class you wanted, and then printing the allowedsubjects directly.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search