5

Out of curiosity, is there another way to extract a subset of my AoH structure? The AoH is 'rectangular' (i.e. guaranteed to have the same keys across all hashrefs).

The use of a temp var and nested maps seems a bit too much for what is essentially a fancy hash slice:

use strict;
use warnings;
use Data::Dump 'dump';

my $AoH = [ # There are many more keys in the real structure

            { a => "0.08", b => "0.10", c => "0.25" },
            { a => "0.67", b => "0.85", c => "0.47" },
            { a => "0.06", b => "0.57", c => "0.84" },
            { a => "0.15", b => "0.67", c => "0.90" },
            { a => "1.00", b => "0.36", c => "0.85" },
            { a => "0.61", b => "0.19", c => "0.70" },
            { a => "0.50", b => "0.27", c => "0.33" },
            { a => "0.06", b => "0.69", c => "0.12" },
            { a => "0.83", b => "0.27", c => "0.15" },
            { a => "0.74", b => "0.25", c => "0.36" },
          ];

# I just want the 'a's and 'b's

my @wantedKeys = qw/ a b /;  # Could have multiple unwanted keys in reality

my $a_b_only = [
                  map { my $row = $_;
                        +{
                           map { $_ => $row->{$_} } @wantedKeys
                         }
                  }
                  @$AoH
               ];

dump $a_b_only; # No 'c's here
Zaid
  • 36,680
  • 16
  • 86
  • 155
  • 1
    I think it probably is, and I suspect you'll be doing this often if you work with rectangular AoHs like that, so I'd suggest writing a function called `project()` that does this transformation for an arbitrary AoH and "column" list. – j_random_hacker Nov 13 '11 at 15:18
  • I agree with j_random_hacker: the posted solution seems fine, but readability can be improved considerably by writing the core functionality as a separate function. For example, `select_from_hash(HASH_REF, ARRAY_REF_OF_WANTED_KEYS)`. – FMc Nov 13 '11 at 17:38

4 Answers4

3

If you do not need $AoH anymore, you can use the destructive way:

delete $_->{c} for @$AoH;
choroba
  • 231,213
  • 25
  • 204
  • 289
3

This does it with one map and an arbitrary list of keys:

my @wantedKeys = qw/a b/;
my $wanted = [
    map { my %h; @h{@wantedKeys} = @{ $_ }{@wantedKeys}; \%h }  @$AoH
];

(With a little help from this post)

Community
  • 1
  • 1
MisterEd
  • 1,725
  • 1
  • 14
  • 15
1

You want delete.

my $foo = [ map { delete $_->{c}; $_  } @$AoH ];

If you want to preserve the original data, then you would need to dereference the hashes first.

my $foo = [ map { my %hash = %$_; delete $hash{c}; \%hash; } @$AoH ];
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • I had a more generic solution in mind where I have multiple columns that I don't want. The 'a','b', 'c' example was just to cut down on verbosity. – Zaid Nov 13 '11 at 15:22
1

This is my solution (let me introduce the nice Data::Printer module):

use Modern::Perl;
use Data::Printer { colored => 1 };

my $AoH = [
            { a => "0.08", b => "0.10", c => "0.25" },
            { a => "0.67", b => "0.85", c => "0.47" },
            { a => "0.06", b => "0.57", c => "0.84" },
            { a => "0.15", b => "0.67", c => "0.90" },
            { a => "1.00", b => "0.36", c => "0.85" },
            { a => "0.61", b => "0.19", c => "0.70" },
            { a => "0.50", b => "0.27", c => "0.33" },
            { a => "0.06", b => "0.69", c => "0.12" },
            { a => "0.83", b => "0.27", c => "0.15" },
            { a => "0.74", b => "0.25", c => "0.36" },
          ];

# I just want the 'a's and 'b's, so I build a new hash with the keys I want
my @ab = map { {a=>$_->{a}, b=>$_->{b}} } @$AoH;
p @ab;

# If you don't mind remove the "c" key in your original structure:
#  map { delete $_->{c} } @$AoH;
#  and $AoH is an array of hashes without the "c" key.
Miguel Prz
  • 13,718
  • 29
  • 42
  • Interesting module there! Note that the keys could be dynamic in nature so I don't have the luxury (nor the patience) to hardcode the keys in. – Zaid Nov 13 '11 at 16:12