On 03/08/2011 19:12, Marc wrote:
>
> I'm trying to sort a shopping cart basket on the item numbers. The
> basket is stored in a hash. There is a hashref called
> %{$main::global->{cart}} that Data::Dumper prints out like so:
> 
> $VAR1 = {
>            '1' =>  '1 1       SL-8206                                         
> 73.15                                   Label 8.25" x 6"                0.8   
>   73.15   ',
>            '3' =>  '3 1       WR-9253                                         
> 13.98                                   Label - 3" x 9"                 0.5   
>   13.98   ',
>            '2' =>  '2 1       APT-46V                                         
> 96.43                                   4"x6" Label, hook               1.8   
>   96.43   '
>          };
> 
> I would like to grab the item numbers, i.e. SL-8206, to sort the cart
> on. Could someone point me to something to read up on this? What is
> the above actually? It looks to me like a hash of hashes of
> arrays(?).

Hi Marc

Take a look at

  perldoc perlreftut

and

  perldoc perlref

to read up on nested data structures. But what you have here is a simple
hash - there is no nesting at all unless you count {cart} which is an
element of the hash referenced by $global.

The hash %{$global->{cart}} has three elements, with keys '1', '3' and
'2' and values equal to the long string the other side of =>. There is
nothing special about those values - they are simple strings that happen
to have several prices of information in them, separated by whitespace.

> I thought that converting it into an array would help, like so:
> 
> my $n = keys($main::global->{cart});

I think this can't be what you wrote - it wouldn't compile. You probably
want

  my $n = keys %{$global->{cart}};

> my @cart_lineitems = @{$main::global->{cart}}{0 .. $n};

That is one way of doing things, but I am surprised you happened upon it
without knowing more about Perl. You have written a hash slice that
indexes the array using integers. But hash keys are strings, and it is
fortunate that Perl converts numbers to strings appropriately for this
hash. (For instance, the element $global->{cart}{'1'} is different and
separate from the element $global->{cart}{'01'}.)

I would write

  my @cart_lineitems;
  foreach my $i (keys  %{global->{cart}}) {
    $cart_lineitems[$i] = $global->{cart}{$i};
  }

although the functionality is equivalent and some would say this way
involves unnecessary code.

> but dumping the output:
> 
> print {$tracelog_fh} Dumper($cart_lineitems[0]);
> print {$tracelog_fh} Dumper($cart_lineitems[1]);
> print {$tracelog_fh} Dumper($cart_lineitems[2]);
> print {$tracelog_fh} Dumper($cart_lineitems[3]);
> 
> gives me this:
> 
> $VAR1 = '';
> $VAR1 = '1    1       SL-8206                                         73.15   
>                                 Label 8.25" x 6"                0.8     73.15 
>   ';
> $VAR1 = '2    1       APT-46V                                         13.98   
>                                 Label - 3" x 9"                 1.8     13.98 
>   ';
> $VAR1 = '3    1       WR-9253                                         96.43   
>                                 4"x6" Label, hook               0.5     96.43 
>   ';
> 
> Why the first one is empty is beyond me, but that's another story.

The first element is empty because you have assigned values at indices
[1], [2] and [3]. The first element is at [0] and you have left it
untouched.

> I then tried to grab just the item numbers using both:
> 
> print {$tracelog_fh} Dumper($cart_lineitems[1][2]);
> 
> and
> 
> print {$tracelog_fh} Dumper($main::global->{cart}->{1}->{2});
> 
> but they produce these errors:
> 
> Can't use string ("1  1       SL-8206                                         
> 73.15                                   Label "...) as an ARRAY ref while 
> "strict refs" in use
> 
> Can't use string ("1  1       SL-8206                                         
> 73.15                                   Label "...) as an HASH ref while 
> "strict refs" in use

Because the values of the array elements are simple strings, as I
explained above, you must find a way of splitting them into
individual fields. The simple way would be to use the 'split' operator
to divide the line at whitespace, but the presence of spaces in the
description field spoils that approach. Without knowing more about your
data, I can suggest that you split on sequences of two or more
whitespace characters, like this

  my @cart_lineitems;
  foreach my $i (keys  %{$global->{cart}}) {
    $cart_lineitems[$i] = [ split /\s{2,}/, $global->{cart}{$i} ];
  }

which dumps like this

@cart_lineitems = (
          undef,
          [
            '1 1 SL-8206',
            '73.15',
            'Label 8.25" x 6"',
            '0.8 73.15 '
          ],
          [
            '2 1 APT-46V',
            '96.43',
            '4"x6" Label, hook',
            '1.8 96.43 '
          ],
          [
            '3 1 WR-9253',
            '13.98',
            'Label - 3" x 9"',
            '0.5 13.98 '
          ]
        );

Which is reasonable, but you still have trailing spaces at the end of
the final field, which may or may not be a problem.

> Anyway, maybe I'm going about this the wrong way. I know enough just 
> to be dangerous at this point. The bottom line is, how would I go
> about grabbing the item numbers from the original hashref so that I
> can sort the cart on them? I'm over my head with this one, so any
> pointers would be extremely helpful. I'm reading about references in
> the "Beginning Perl" book, but so far the light hasn't come on.

Grabbing just the item numbers (the third field) doesn't involve any
column that can contain embedded spaces, so you can just sort on the
value of

  ( split ' ', $lineitem )[2]

as shown in the program below. Depending on what else you want to do
with your data, it may well be better to store it in a different format,
but I hope this serves to help you with your initial problem.

Cheers,

Rob


use strict;
use warnings;

use Data::Dumper;

our $global;
$global->{cart} = {
          '1' => '1 1 SL-8206           73.15         Label 8.25" x 6"    0.8 
73.15 ',
          '3' => '3 1 WR-9253           13.98         Label - 3" x 9"     0.5 
13.98 ',
          '2' => '2 1 APT-46V           96.43         4"x6" Label, hook     1.8 
96.43 ',
};

my @cart_lineitems = sort {
  ( split ' ', $a)[2] cmp ( split ' ', $b)[2];
} values %{$global->{cart}};

print Data::Dumper->Dump([\@cart_lineitems], ['*cart_lineitems']);

**OUTPUT**

@cart_lineitems = (
                    '2 1 APT-46V           96.43         4"x6" Label, hook     
1.8 96.43 ',
                    '3 1 WR-9253           13.98         Label - 3" x 9"     
0.5 13.98 ',
                    '1 1 SL-8206           73.15         Label 8.25" x 6"    
0.8 73.15 '
                  );

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to