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

Oh wise and knowledgeable monks. I seek your wisdom in this hopefully interesting dilemma (ok, enough of that ...). I'm trying to split an array of hashes by a timestamp within the list using map. So far here is what I have.
my @prizes = [ { 'GivenAway' => undef, 'Breakdown' => '0', 'Dcode' => '00000', 'UserId' => '8853', 'Prize' => '500', 'Contracts' => [ { 'Year' => undef, 'Make' => undef, 'Model' => undef, 'Contract' => '1' } ], 'Type' => 'prizes', 'Timestamp' => '2005-11-07 11:18:01', 'WinnerId' => '2026', 'lineid' => '2026', 'Count' => '1', 'Rate' => 'std' }]; my %month = ( '01' => 'January', '02' => 'February', '03' => 'March', '04' => 'April', '05' => 'May', '06' => 'June', '07' => 'July', '08' => 'August', '09' => 'September', '10' => 'October', '11' => 'November', '12' => 'December', ); my @mapped_prizes = map +{ $month{(split(/-| /,$_->{'Timestamp'}))[1]} + => $_ } , @prizes; ## Which hopefully yields 'November' => [{ 'GivenAway' => undef, 'Breakdown' => '0', 'Dcode' => '00000', 'UserId' => '8853', 'Prize' => '500', 'Contracts' => [ { 'Year' => undef, 'Make' => undef, 'Model' => undef, 'Contract' => '1' } ], 'Type' => 'prizes', 'Timestamp' => '2005-11-07 11:18:01', 'WinnerId' => '2026', 'lineid' => '2026', 'Count' => '1', 'Rate' => 'std'}, ];
Sorry about the formatting. I did the best I can with the room I had. Hopefully you get the idea of what I wanted to do. I'm not sure if I should use map +{ } or map +( ). In any case, dumping @mapped_prizes only results in confusion as I'm not sure if its doing what I want it to do. With map +{} Dumper() yields
######MAPPED PRIZES###### $VAR1 = { 'November' => { 'GivenAway' => undef, 'Breakdown' => '0', 'Dcode' => '00000', 'UserId' => '8853', 'Prize' => '500', 'Contracts' => [ { 'Year' => undef, 'Make' => undef, 'Model' => undef, 'Contract' => '1' } ], 'Type' => 'prizes', 'Timestamp' => '2005-11-07 11:18:01', 'WinnerId' => '2026', 'lineid' => '2026', 'Count' => '1', 'Rate' => 'std' } }; $VAR2 = { 'November' => { 'GivenAway' => undef, 'Breakdown' => '0', 'Dcode' => '00000', 'UserId' => '8853', 'Prize' => '300', 'Contracts' => [ { 'Year' => undef, 'Make' => undef, 'Model' => undef, 'Contract' => '100' } ], 'Type' => 'prizes', 'Timestamp' => '2005-11-07 15:06:39', 'WinnerId' => '2027', 'lineid' => '2027', 'Count' => '1', 'Rate' => 'std' } };
And with map +() Dumper() yields:
######MAPPED PRIZES###### $VAR1 = 'November'; $VAR2 = { 'GivenAway' => undef, 'Breakdown' => '0', 'Dcode' => '00000', 'UserId' => '8853', 'Prize' => '500', 'Contracts' => [ { 'Year' => undef, 'Make' => undef, 'Model' => undef, 'Contract' => '1' } ], 'Type' => 'prizes', 'Timestamp' => '2005-11-07 11:18:01', 'WinnerId' => '2026', 'lineid' => '2026', 'Count' => '1', 'Rate' => 'std' }; $VAR3 = 'November'; $VAR4 = { 'GivenAway' => undef, 'Breakdown' => '0', 'Dcode' => '00000', 'UserId' => '8853', 'Prize' => '300', 'Contracts' => [ { 'Year' => undef, 'Make' => undef, 'Model' => undef, 'Contract' => '100' } ], 'Type' => 'prizes', 'Timestamp' => '2005-11-07 15:06:39', 'WinnerId' => '2027', 'lineid' => '2027', 'Count' => '1', 'Rate' => 'std' };
Clever use of map? Or a clever shot in the foot? My thanks, BMaximus
BMaximus

Replies are listed 'Best First'.
Re: Is this a correct use of map?
by Aristotle (Chancellor) on Nov 08, 2005 at 00:04 UTC

    I think you want +() or {}, but not +{}. With +{}, you will get one hashref per element – whereas I think you want a single hash, in which case you want either an expression (+()) or a single-expression block ({}). But I can only guess.

    Other than that confusion, your map is fine, if a little hard to read. I’d put the month extraction code in a subroutine so I could give it a descriptive name. Rather than:

    my @mapped_prizes = map +{ $month{(split(/-| /,$_->{'Timestamp'}))[1]} + => $_ }, @prizes;

    I’d write:

    sub month_from_datetime { my ( $datetime ) = @_; ( split m{-| }, $datetime )[1] } my %month_name = ( # ... ); my %mapped_prizes = map { my $month_num = month_from_datetime $_->{'Timestamp'}; $month_name{ $month_num } => $_; }, @prizes;

    which makes it quite obvious what’s going on.

    Makeshifts last the longest.

Re: Is this a correct use of map?
by GrandFather (Saint) on Nov 07, 2005 at 23:41 UTC

    Have you run this with use warnings; use strict;? When I do I get:

    Pseudo-hashes are deprecated at noname2.pl line 41. Argument "2005-11-07 11:18:01" isn't numeric in hash element at noname +2.pl line 41. Use of uninitialized value in split at noname2.pl line 41. Use of uninitialized value in hash element at noname2.pl line 41. Use of uninitialized value in anonymous hash ({}) at noname2.pl line 4 +1.

    which sort of indicates a problem. Note that this happens even if I replace the undef values with values.


    Perl is Huffman encoded by design.
      I have use warnings; use strict; on and I get no errors or warnings probably because its just a small snippet of a bigger picture that I tried to shrink so I wouldn't bore you with the rest of the code. I'm looking to see if I created the right block to do what I put at the bottom of the code. I guess if it can't be run it really down't help explain what needs to be done. I tried my best to explain. Unfortunately it wasn't good enough.
      BMaximus

        Try altering the following code to show your problem if it doesn't do what you are trying to achieve already:

        use strict; use warnings; use Data::Dumper; my @prizes = ( { 'Timestamp' => '2005-11-07 11:18:01', 'WinnerId' => '2026', 'lineid' => '2026', }, { 'Timestamp' => '2005-01-07 11:18:01', 'WinnerId' => '2001', 'lineid' => '2001', }, { 'Timestamp' => '2005-05-07 11:18:01', 'WinnerId' => '2015', 'lineid' => '2015', }, ); my %month = ( '01' => 'January', '02' => 'February', '03' => 'March', '04' => 'April', '05' => 'May', '06' => 'June', '07' => 'July', '08' => 'August', '09' => 'September', '10' => 'October', '11' => 'November', '12' => 'December', ); my @mapped_prizes = map {[$month{(split (/-/, $_->{'Timestamp'}))[1]} +=> $_]} @prizes; print Dumper (\@mapped_prizes);

        Prints:

        $VAR1 = [ [ 'November', { 'Timestamp' => '2005-11-07 11:18:01', 'lineid' => '2026', 'WinnerId' => '2026' } ], [ 'January', { 'Timestamp' => '2005-01-07 11:18:01', 'lineid' => '2001', 'WinnerId' => '2001' } ], [ 'May', { 'Timestamp' => '2005-05-07 11:18:01', 'lineid' => '2015', 'WinnerId' => '2015' } ] ];

        Note that I removed some of the fields from the hash - only a couple are needed to demonstrate the issue. Note also that I added a couple of entries because it seems that more than one is required to show the issue. And further, note that I reduced the reference nesting by a level in the @prizes array which cleans up the warnings that I was seeing and also that I changed the +{}, in your original map (that looks rather peculiar) to a more usual {} and altered the contents of the map expression to do what I guess you want to do: generate an list of pairs of month and prize elements. I don't see why you don't want this as a hash however.


        Perl is Huffman encoded by design.