in reply to Re: How to reference to array keys?
in thread How to reference to array keys?


Hey Marshall sorry to double post, but you don't have to answer my previous question about that if statement, it does work it's just that everything below that if statement looks like it's quoted (text is pink, means quote in gedit). If I am thinking correctly it just checks for line that start with a "/". Right?
I wasn't able to get it working because I didn't have the DATA::Dump package, but I do now and the ouput looks pretty good. Nice Work!

Sorry for the newbieism but what does it mean when you have the lines with the array then curly braces with it like this line below?
push @{$recordState{$record_id}{$OwnerOrWaiting}}, $_;
Could you explain that to me?

Thanks, Matt

Replies are listed 'Best First'.
Re^3: How to reference to array keys?
by choroba (Cardinal) on Jul 27, 2011 at 15:22 UTC

      Good info! Thanks, I'm studying it now...


      Thanks, Matt

      Alright, so I have been reading the perl docs stuff online about references for most of the day.
      Most of it is for much easier stuff than Marshal had written in his example. On lines where Marshal uses references to a hash of hashes of arrays (I think???), could someone explain them to me I am not getting it?

      For Example:
      push @{$recordState{$record_id}{$OwnerOrWaiting}}, $_; if ( @{$recordState{$recNum}{WAITING}} >= 1) foreach my $line ( @{$recordState{$recNum}{WAITING}} )


      I know that, lets say:
      $myArray = \@array; is the same as @{$myArray}, which is referring to the array "@array"
      -OR-
      $myHash = \%hash is the same as %{$myHash}, which refers to the hash "%hash", I think????

      Also, that square brackets after a reference is referring to an element in that array. Like this, %{$myArray}[3] refers to the 4th element in the array it refers to.
      And for a hash reference, keys %myHash is the same as, keys %{$myHash}.


      Or what would be even more helpful, if you or anyone has some time, could you take Marshal's code and document it out to where a newbie could relate (i.e. comments before any of the more difficult lines)?

      If this is too much trouble, I understand, it's alot of work. I mean I could just take the code and probably use it as is, but I really want to learn this stuff.

      Extremely Thankful,
      Matt

        Matt,
        I rewrote this with a different data structure, this is just a simple array of lines (an Array of references to lines).
        Study the info you have been given.
        What you want is relatively complicated to do. But I figure that you are motivated enough to get it done.

        This code dumps the basic data in a 1st report.
        The 2nd report shows the the folks who own a file and the other guys who want it. The report specifically excludes those who own it and want it themselves.

        So the data structure is easier to understand, but the price is that it is a bit more convoluted to fiddle with.

        I'm sure that the other kind Monks and I will be willing to help as you have other questions.

        #!/usr/bin/perl use strict; use warnings; use Data::Dump qw(pp); #Data::Dumper is also great! $|=1; #turn off STDOUT buffering my @records; my $OwnerOrWaiting=""; while (<DATA>) { next if /^\s*$/; # skip whitespace lines s/\s+$//; # delete all trailing whitespace # this does a chomp() and a bit more.. if (/^FILENAME/) # FILENAME line defines what col #4 means { $OwnerOrWaiting = (split)[3]; } if (m/^\//) # A data line starts with '/' # I don't like "leaning toothpick" but # ok if your text editor displays wrong # colors with the other syntax - no biggie { push @records, "$OwnerOrWaiting $_"; #add status to line } } sub get_fields { my $line = shift; my %fields; @fields{qw(OWNER-WAIT FILENAME RECORD_ID M USER UNBR UNO TTY TIME D +ATE)} = split(' ', $line, 10); return %fields; } print "Dumping raw records....\n"; foreach my $line (@records) { my ($colnumber1, @rest) = split(' ',$line); printf "%-8s @rest\n", $colnumber1; } # lets print lines where we have an OWNER and at least one # other person WAITING who is not the OWNER print "\n\n"; my $current_owner=""; my $first_record=0; my @lines_in_record=(); my %temp; foreach my $line (@records) { %temp = get_fields($line); #make hash of field names if ( $temp{'OWNER-WAIT'} eq 'OWNER') # OWNER LINE { process_owner_record(); } else # WAITING LINE { push @lines_in_record, $line; } } process_owner_record(); sub process_owner_record { if (!$current_owner) { $current_owner = $temp{USER}; return; } my $new_owner = $temp{'USER'}; foreach (@lines_in_record) { my %this_record= get_fields($_); print "owner=$current_owner $_\n" if $current_owner ne $this_record{USER}; } @lines_in_record = (); $current_owner = $new_owner; } =prints Dumping raw records.... OWNER /prod-data/J 00151120273 X jmorg 3584038 247 ts/49 13:38:12 J +ul 20 WAITING /prod-data/J 00151120273 X jmorg 2015244 134 s/109 13:48:32 J +ul 20 WAITING /prod-data/J 00151120273 X gdavi 1359996 62 ts/20 13:54:22 Ju +l 20 OWNER /prod-data/J 001!L!311895 X jmorg 2015244 134 s/109 13:48:32 +Jul 20 WAITING /prod-data/J 001!L!311895 X jmorg 5713932 191 ts/46 14:01:42 +Jul 20 OWNER /prod-datahi 001!10274882 X rfuse 3354796 61 ts/43 13:39:02 J +ul 20 WAITING /prod-datahi 001!10274882 X jmorg 3584038 247 ts/49 13:39:22 +Jul 20 owner=jmorg WAITING /prod-data/J 00151120273 X gdavi 1359996 62 + ts/20 13:54:22 Jul 20 owner=rfuse WAITING /prod-datahi 001!10274882 X jmorg 3584038 24 +7 ts/49 13:39:22 Jul 20 =cut
Re^3: How to reference to array keys?
by Marshall (Canon) on Jul 27, 2011 at 20:35 UTC
    Hey Matt, extra post is no problem at all.
    If I am thinking correctly it just checks for line that start with a "/". Right? Yes, Right!
    I see you have a link to some more info on references, I'll hit a few highlights specific to this code.

    %recordState is a hash with basically 2 keys. In a complex data structure, everything is a reference until you get to the very last dimension where the data is. The value of $recordState{$record_id} is a reference to a another hash. The key to that hash is $OwnwerOrWaiting which is either set to "OWNER" or "WAITING" and the value is a reference to an array of input lines. Look at the output of Data::Dump and see the "key => value" pairs.

    Also take a look at my dump loop, foreach my $recHashref ( values %recordState). There I didn't even use the $record_id key at all! I just get the values of the first dimension hash, where are references to the 2nd dimension hash. In the line
    print "WAITING $_\n",  for @{$recHashref->{WAITING}}; $recHashref is dereferenced and the WAITING key is accessed. The values of that key is a reference to an array of lines. I say that that whole thing, $recHashref->{WAITING} is an array reference that I want to dereference by enclosing it in another set of curly braces and putting an @ in front. Each line gets printed out. Note that I used the exact same code pattern for OWNER as for WAITING. There is only one OWNER and that could have been:
    print "OWNER   $recHashref->{OWNER}[0]\n"; which would mean give me the 0th line in the array pointed to by $recHashref->{OWNER}. There is a certain value in uniformity and so I did not handle the case of just one OWNER separately.

    Maybe I confused you even more, but it this was remotely understandable, then the answer to you question above is that value of $recordState{$record_id}{$OwnerOrWaiting} is a reference to an array, which is dereferenced with the @ so that the current line can be pushed onto it.

    It could very well be that the data structure can be simplified once I read more about what you are needing as an end result.

      Hey Marshal,

      Thank you very much for taking the time to explain things to me. I will start going over all the info you gave me, and I will reply back in a little while after I gain some headway with this.


      Thanks, Matt


      Hey Marshal,

      I've defiantly made some headway with the new simplified version that you gave me. But I just have one questions about it at the moment.

      1. For the section in the code where it Dumps the raw records,
      foreach my $line (@records) { (my $colnumber1, @rest) = split(' ',$line); printf "%-8s @rest\n", $colnumber1; }
      how does the first line in the loop (one with the 'split' function) work?
      I get that your creating and assigning 2 new variables, but how does it work setting one split function equal to 2 different variables (and 2 different types of variables)? By doing 2 print statements inside that loop, one fore each variable, I can see that:
      $colnumber1 = either 'OWNER' -or- 'WAITING'
      @rest = one whole line of data not including 'OWNER' or 'WAITING'


      UPDATE
      Came across one other question for the moment.
      In the same file what does the line if (!$current_owner) check for if $current_owner has no value? Or does it?


      Thanks,
      Matt


        The line with split works this way: First of all the left side of the equation is in parentheses, so it provides list context to the left side (many functions return different things in different contexts, see the first two paragraphs of split

        So the split in list context returns a list of strings that get distributed to the list on the left side of the equation. This list begins with a scalar, so the first item in the list is stored in the scalar. The second variable is an array and arrays just take everything they can get, so all the other strings are pushed into @rest. If there were another array or scalar at the end of the list on the left side, it would be empty. If another scalar were before @rest, it would hold the second item of the list of strings

        (!$current_owner) is true when $current_owner is false. $current_owner is false if it is undef, the empty string ("") or 0. Since $current_owner is initialized with the empty string, this condition is at least true the first time the subroutine process_owner_record is called.