need help with hash - been too long working in Perl

Discussion in 'Perl Misc' started by JerryP, Oct 27, 2007.

  1. JerryP

    JerryP Guest

    Hi!

    This is simple? But it has been a while that I have programmed in
    Perl. What I am wanting to do is build a hash from a text file:

    text:

    79706-0000 2229.17
    79706-0000 2523.25
    79701-0000 53904.48
    79701-0000 78957.81
    79701-0000 378043.04
    79701-0000 1255172.34
    79702-0000 7367.23
    79702-0000 20742.95
    79702-0000 67331.82
    79702-0000 137629.57
    79703-0000 1444.18
    79701-0000 57565.48
    79703-0000 2415.00
    79703-0000 2787.97
    79703-0000 4780.55
    79703-0000 5061.21
    79703-5011 1125.80
    79704-0000 2382.31
    79705-0000 4612.65
    79706-0000 1416.50
    79703-0000 64014.50

    With script:

    use strict;
    local( *FI, *FO );
    my @text = ();
    my @zip = ();
    my %ref;

    open ( FI, "msj_sare.lst" ) or die "Couldn't open c:\\vf\
    \sj_sare.lst";
    my @text_ = <FI>;
    close FI;

    s/\n// for( @text = @text_ );

    foreach ( @text ) {
    /(\d+)\-(\d+)(\s+)(-?(?:\d+(?:\.\d*)?|\.\d+))/;
    push( @zip, $1 );
    push( @{ $ref{ $1 }{ $2 }},$_ );
    }

    # then sort with

    open ( FO, "+>msj_sare.jwp" ) or die "Couldn't open c:\\vf\
    \sj_sare.jwp";

    foreach my $family ( sort keys %ref ) {

    # for my $role ( sort { $ref{$b} <=> $ref{$a} } keys %
    { $ref{$family} } ) {
    print " $family*$ref{ $family }*\n";

    for my $role ( sort keys %{ $ref{$family} } ) {
    print(join(', ',sort keys ${ $ref{$family} }),"\n");
    # print "$ref{$family}{$role}[0]\n";
    print FO "$ref{$family}{$role}[0]\n";
    }
    print FO "\n";
    }


    I am wanting to print out the data in the following format:

    79701-0000 1255172.34
    79701-0000 378043.04
    79701-0000 78957.81
    79701-0000 57565.48
    79701-0000 53904.48

    79702-0000 137629.57
    79702-0000 67331.82
    79702-0000 20742.95
    79702-0000 7367.23

    79703-0000 64014.50
    79703-0000 5061.21
    79703-0000 2787.97
    79703-0000 2415.00
    79703-0000 4780.55
    79703-0000 1444.18
    79703-5011 1125.80

    79704-0000 2382.31

    79705-0000 4612.65

    79706-0000 2523.25
    79706-0000 2229.17
    79706-0000 1416.50

    Thanks,

    Jerry
     
    JerryP, Oct 27, 2007
    #1
    1. Advertising

  2. JerryP

    Ron Bergin Guest

    My system seamed to hang while posting, so this may end up as a double
    post.

    On Oct 27, 12:57 pm, JerryP <> wrote:
    > Hi!
    >
    > This is simple? But it has been a while that I have programmed in
    > Perl. What I am wanting to do is build a hash from a text file:
    >
    > text:
    >
    > 79706-0000 2229.17
    > 79706-0000 2523.25
    > 79701-0000 53904.48
    > 79701-0000 78957.81
    > 79701-0000 378043.04
    > 79701-0000 1255172.34
    > 79702-0000 7367.23
    > 79702-0000 20742.95
    > 79702-0000 67331.82
    > 79702-0000 137629.57
    > 79703-0000 1444.18
    > 79701-0000 57565.48
    > 79703-0000 2415.00
    > 79703-0000 2787.97
    > 79703-0000 4780.55
    > 79703-0000 5061.21
    > 79703-5011 1125.80
    > 79704-0000 2382.31
    > 79705-0000 4612.65
    > 79706-0000 1416.50
    > 79703-0000 64014.50
    >
    > With script:
    >
    > use strict;
    > local( *FI, *FO );

    Why are you using local on the file handles, which appear to have file
    scope?

    > my @text = ();
    > my @zip = ();

    It doesn't hurt, but there is no need to initialize the arrays with an
    empty list.

    > my %ref;
    >
    > open ( FI, "msj_sare.lst" ) or die "Couldn't open c:\\vf\
    > \sj_sare.lst";

    You should be using the 3 arg form of open and you should probably
    include $! in the die statement to output the reason why it failed.

    > my @text_ = <FI>;
    > close FI;

    It's almost never a good idea to slurp the entire file into an array.
    Instead, you should loop through it.
    >
    > s/\n// for( @text = @text_ );

    Use chomp while looping through the file to remove \n.

    >
    > foreach ( @text ) {
    > /(\d+)\-(\d+)(\s+)(-?(?:\d+(?:\.\d*)?|\.\d+))/;
    > push( @zip, $1 );
    > push( @{ $ref{ $1 }{ $2 }},$_ );
    > }

    This is a personal preference, but I'd simplify the regex and use 1
    push instead of 2.
    >
    > # then sort with
    >
    > open ( FO, "+>msj_sare.jwp" ) or die "Couldn't open c:\\vf\
    > \sj_sare.jwp";
    >
    > foreach my $family ( sort keys %ref ) {
    >
    > # for my $role ( sort { $ref{$b} <=> $ref{$a} } keys %
    > { $ref{$family} } ) {
    > print " $family*$ref{ $family }*\n";
    >
    > for my $role ( sort keys %{ $ref{$family} } ) {
    > print(join(', ',sort keys ${ $ref{$family} }),"\n");
    > # print "$ref{$family}{$role}[0]\n";
    > print FO "$ref{$family}{$role}[0]\n";
    > }
    > print FO "\n";
    > }
    >
    > I am wanting to print out the data in the following format:
    >
    > 79701-0000 1255172.34
    > 79701-0000 378043.04
    > 79701-0000 78957.81
    > 79701-0000 57565.48
    > 79701-0000 53904.48
    >
    > 79702-0000 137629.57
    > 79702-0000 67331.82
    > 79702-0000 20742.95
    > 79702-0000 7367.23
    >
    > 79703-0000 64014.50
    > 79703-0000 5061.21
    > 79703-0000 2787.97
    > 79703-0000 2415.00
    > 79703-0000 4780.55
    > 79703-0000 1444.18
    > 79703-5011 1125.80
    >
    > 79704-0000 2382.31
    >
    > 79705-0000 4612.65
    >
    > 79706-0000 2523.25
    > 79706-0000 2229.17
    > 79706-0000 1416.50
    >
    > Thanks,
    >
    > Jerry


    use strict;
    use warnings;

    my %data;
    while(<DATA>) {
    my ($key) = /^(\d+)/;
    my ($subkey, $value) = split /\s+/;
    push @{$data{$key}{$subkey}}, $value;
    }

    foreach my $key ( sort keys %data ) {
    foreach my $subkey ( sort keys %{$data{$key}} ) {
    foreach my $value ( sort {$b <=> $a} @{$data{$key}{$subkey}} ) {
    printf "%s %12.2f\n", $subkey, $value;
    }
    }
    print "\n";
    }


    __DATA__
    79706-0000 2229.17
    79706-0000 2523.25
    79701-0000 53904.48
    79701-0000 78957.81
    79701-0000 378043.04
    79701-0000 1255172.34
    79702-0000 7367.23
    79702-0000 20742.95
    79702-0000 67331.82
    79702-0000 137629.57
    79703-0000 1444.18
    79701-0000 57565.48
    79703-0000 2415.00
    79703-0000 2787.97
    79703-0000 4780.55
    79703-0000 5061.21
    79703-5011 1125.80
    79704-0000 2382.31
    79705-0000 4612.65
    79706-0000 1416.50
    79703-0000 64014.50
     
    Ron Bergin, Oct 27, 2007
    #2
    1. Advertising

  3. JerryP wrote:
    >
    > This is simple? But it has been a while that I have programmed in
    > Perl. What I am wanting to do is build a hash from a text file:
    >
    > text:
    >
    > 79706-0000 2229.17
    > 79706-0000 2523.25
    > 79701-0000 53904.48
    > 79701-0000 78957.81
    > 79701-0000 378043.04
    > 79701-0000 1255172.34
    > 79702-0000 7367.23
    > 79702-0000 20742.95
    > 79702-0000 67331.82
    > 79702-0000 137629.57
    > 79703-0000 1444.18
    > 79701-0000 57565.48
    > 79703-0000 2415.00
    > 79703-0000 2787.97
    > 79703-0000 4780.55
    > 79703-0000 5061.21
    > 79703-5011 1125.80
    > 79704-0000 2382.31
    > 79705-0000 4612.65
    > 79706-0000 1416.50
    > 79703-0000 64014.50
    >
    > With script:
    >
    > use strict;
    > local( *FI, *FO );


    You really don't need to local()ize those typeglobs.

    > my @text = ();
    > my @zip = ();
    > my %ref;
    >
    > open ( FI, "msj_sare.lst" ) or die "Couldn't open c:\\vf\
    > \sj_sare.lst";


    You are trying to open "msj_sare.lst" but your error message says you
    tried to open "c:\\vf\\sj_sare.lst"? You should include the $! (or $^E)
    variable in the error message so you know *why* the open failed.

    > my @text_ = <FI>;
    > close FI;
    >
    > s/\n// for( @text = @text_ );
    >
    > foreach ( @text ) {
    > /(\d+)\-(\d+)(\s+)(-?(?:\d+(?:\.\d*)?|\.\d+))/;


    You shouldn't use the numeric variables unless the match was successful
    or they will contain values from the last successful match. You are
    capturing $3 and $4 but you are not using their contents?

    > push( @zip, $1 );
    > push( @{ $ref{ $1 }{ $2 }},$_ );
    > }
    >
    > # then sort with
    >
    > open ( FO, "+>msj_sare.jwp" ) or die "Couldn't open c:\\vf\
    > \sj_sare.jwp";


    You are trying to open "msj_sare.jwp" but your error message says you
    tried to open "c:\\vf\\sj_sare.jwp"? You are opening the file for both
    reading and writing but you are not reading from the file? You should
    include the $! (or $^E) variable in the error message so you know *why*
    the open failed.

    > foreach my $family ( sort keys %ref ) {
    >
    > # for my $role ( sort { $ref{$b} <=> $ref{$a} } keys %
    > { $ref{$family} } ) {
    > print " $family*$ref{ $family }*\n";
    >
    > for my $role ( sort keys %{ $ref{$family} } ) {
    > print(join(', ',sort keys ${ $ref{$family} }),"\n");
    > # print "$ref{$family}{$role}[0]\n";
    > print FO "$ref{$family}{$role}[0]\n";
    > }
    > print FO "\n";
    > }
    >
    > I am wanting to print out the data in the following format:
    >
    > 79701-0000 1255172.34
    > 79701-0000 378043.04
    > 79701-0000 78957.81
    > 79701-0000 57565.48
    > 79701-0000 53904.48
    >
    > 79702-0000 137629.57
    > 79702-0000 67331.82
    > 79702-0000 20742.95
    > 79702-0000 7367.23
    >
    > 79703-0000 64014.50
    > 79703-0000 5061.21
    > 79703-0000 2787.97
    > 79703-0000 2415.00
    > 79703-0000 4780.55
    > 79703-0000 1444.18
    > 79703-5011 1125.80
    >
    > 79704-0000 2382.31
    >
    > 79705-0000 4612.65
    >
    > 79706-0000 2523.25
    > 79706-0000 2229.17
    > 79706-0000 1416.50


    It *looks* like you might want the second column in sorted order but the
    line:

    79703-0000 4780.55

    is not in sorted order?

    Perhaps you want something like this:

    use warnings;
    use strict;

    open FI, '<', 'msj_sare.lst' or die "Couldn't open 'msj_sare.lst' $!";
    open FO, '>', 'msj_sare.jwp' or die "Couldn't open 'msj_sare.jwp' $!";

    my %ref;
    while ( <FI> ) {
    if ( /(\d+)-(\d+)\s+-?(?:\d+\.\d*|\.?\d+)/ ) {
    push @{ $ref{ $1 }{ $2 } }, $_;
    }
    }

    for my $family ( sort { $a <=> $b } keys %ref ) {
    for my $role ( sort { $a <=> $b } keys %{ $ref{ $family } } ) {
    print FO @{ $ref{ $family }{ $role } }, "\n";
    }
    }

    __END__



    John
    --
    use Perl;
    program
    fulfillment
     
    John W. Krahn, Oct 28, 2007
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Amanda
    Replies:
    26
    Views:
    961
    amanda
    Nov 11, 2006
  2. Replies:
    0
    Views:
    591
  3. veryhotsausage
    Replies:
    1
    Views:
    1,810
    veryhotsausage
    Jul 4, 2008
  4. rp
    Replies:
    1
    Views:
    537
    red floyd
    Nov 10, 2011
  5. Robert Watkins
    Replies:
    4
    Views:
    116
    Tad McClellan
    Jan 26, 2006
Loading...

Share This Page