iphone has asked for the wisdom of the Perl Monks concerning the following question:

I have a hash %Hash whose keys are names of xml files and values are an array of line/lines present in the xml files.Now i want to print the data of the hash in such a way that only the "keys that have a value" needs to be printed.

For example OUTPUT of my code is as follows

acer.xml' => [], tools.xml' => [], files.xml' => [ 'organize/file/load.c#6''embark/fi +les/data.c#4' ], multimedia.xml' => [],
I want the output to be like
KEYS:files.xml Values:organize/files/load.c#6 embark/files/data.c#4
I tried to use the below code but the values are getting printed as array references and all the keys and values are getting printed.Please help
foreach my $key ( keys %Hash ) { my $value = $Hash{$key}; print "KEYS:$key VALUES:$value\n"; }

Replies are listed 'Best First'.
Re: Printing only the "keys that have a value" in hash
by kcott (Archbishop) on Nov 01, 2010 at 03:22 UTC

    There's a number of things you need to do:

    • Separate the values in [ ... ] with commas or use [ qw{ ... } ]
    • Access the values by dereferencing them: @{$Hash{$key}}
    • Call next when the value is an empty list
    • Change KEYS to KEY - you're only accessing one per loop iteration and stating KEYS could be confusing
    • Add some formatting to get the output you want

    Here's my code - it's only minimally changed from yours - check the notes above.

    #!perl use 5.12.0; use warnings; my %Hash = ( 'acer.xml' => [], 'tools.xml' => [], 'files.xml' => [ 'organize/file/load.c#6','embark/files/data.c#4' +], 'multimedia.xml' => [], 'extra_for_test.xml' => [ qw{ blahA blahB blahC } ], ); foreach my $key ( keys %Hash ) { next unless @{$Hash{$key}}; my $value = join "\n\t", @{$Hash{$key}}; print "KEY:\t$key\nVALUES:\t$value\n"; }

    And here's the output:

    $ xml_hash_prob.pl KEY: extra_for_test.xml VALUES: blahA blahB blahC KEY: files.xml VALUES: organize/file/load.c#6 embark/files/data.c#4

    -- Ken

Re: Printing only the "keys that have a value" in hash
by lostjimmy (Chaplain) on Nov 01, 2010 at 02:56 UTC
    Assuming your input always follows the same pattern, and based off of your other replies, you'll want to do something similar to the following (not tested in the least):
    for my $key (keys %Hash_filematches) { my $value = $Hash_filematches{$key}; if (scalar @$value) { # check that the arrayref isn't empty print "KEY: $key\n"; print "VALUES: ", join(", ", @$value), "\n\n"; } }
      ++ for this reply - it's important to check that the arrayref held in the value for each key actually references a non-empty array - otherwise, I'm guessing that the exists call will always return true, since the arrayref will exist, but potentially reference an empty array.
Re: Printing only the "keys that have a value" in hash
by aquarium (Curate) on Nov 01, 2010 at 01:59 UTC
    an alternative to "exists" would be to undef all the empty hash keys, just prior to your main processing loop, if that suits.
    also looks like your code has outgrown the hard-coded assignment in the hash...so refactoring appropriately would get rid of the need to use "exists".
    the hardest line to type correctly is: stty erase ^H

      I am sorry,I have no idea on what you are saying?

        just before your main processing instructions
        foreach $key(%my_hash) { delete $my_hash{"$key"} if(!exists($my_hash{"$key"})); }
        that will get rid of empty keys--assuming you're not interested in these--and henceforth you can now iterate over keys of the hash.
        the hardest line to type correctly is: stty erase ^H
Re: Printing only the "keys that have a value" in hash
by umasuresh (Hermit) on Nov 01, 2010 at 01:45 UTC
    Try  if(exists $hash{$key}){...}

      I have two problems here 1.Hash values are getting printed as array references. 2.I need to print "only the keys and it's corresponding values" if a value is present for the key

      I tried to use your suggestion but getting the following warning exists argument is not a HASH or ARRAY element at orphan_plf.pl line 58

      foreach my $key ( keys %Hash_filematches ) { my $value = {$Hash_filematches{$key}}; print "$key => $value\n" if(exists {$Hash_filematches{$key}}); }