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

Should preface that this is my first post to ze Monks. And, should preface that I'm still a bit of a newbie when it comes to this, so I oftentimes do things the long way. So, given all that. I was passed a tab-delimited file that contains a bunch of records like this:
1234 5 20021201 1 0 5678 0 20021202 0 0 0 0 0 10 9120 10 20021211 0 0 6543 5 20021202 0 0 0 0 0 5 0 0 0 5
What I want to be able to do is take those elements in a line that are "undef" and replace the undef value with the defined element from the previous line. This is what I've written so far and it prints out the @IDS to show that the replacement I used, actually worked. Next step will be pushing the values back into the original array. Thanks.
#!/usr/bin/perl -w use strict; my @IDS; while (<DATA>) { my @sections = split("\t", $_); my $id = $sections[0]; push @IDS, $id; } my $length = scalar(@IDS); foreach (@IDS) { for (my $i = 0; $i < $length; $i++) { if ($IDS[$i] =~ m/^\s+/) { $IDS[$i] = $IDS[$i-1]; } } } # print scalar(@IDS); print @IDS; __END__
1234 5 20021201 1 0 5678 0 20021202 0 0 0 0 0 10 9120 10 20021211 0 0 6543 5 20021202 0 0 0 0 0 5 0 0 0 5

Replies are listed 'Best First'.
Re: Filling In "The Gaps" in an Array
by particle (Vicar) on Dec 12, 2002 at 01:23 UTC

    create a buffer for the value in question. if the value is null, use the buffered version. otherwise, modify the buffer to the current value.

    there are edge cases i haven't dealt with, but you weren't that specific about functionality in that space. in any case, this should get you in the right direction.

    #!/usr/bin/perl use strict; use warnings; $|++; my $buffer; while( my $record = <DATA> ) { my @items = split /\t/, $record, 5; '' ne $items[0] ? $buffer = $items[0] : $items[0] = $buffer; print join "\t", @items; } =pod prints: 1234 5 20021201 1 0 5678 0 20021202 0 0 5678 0 0 0 10 9120 10 20021211 0 0 6543 5 20021202 0 0 6543 0 0 0 5 6543 0 0 0 5 =cut __DATA__ 1234 5 20021201 1 0 5678 0 20021202 0 0 0 0 0 10 9120 10 20021211 0 0 6543 5 20021202 0 0 0 0 0 5 0 0 0 5

    ~Particle *accelerates*

      Thanks so much for the posts! I'm certain that the approaches will help me out when I get back into the office tomorrow morning. I'll rework the code and repost my results if anyone else is interested. Thanks again.
      Man, my newbie-dom really manifested itself in the form of not being able to see the way you used operators as short hand. I went through my sources though and to put it in newbie terms: This...
      '' ne $items[0] ? $buffer = $items[0] : $items[0] = $buffer;
      ...is the same as this...
      if ('' ne $items[0]) { $buffer = $items[0] } else { $items[0] = $buffer }
      right? I think this is going to work out nicely. Thank you all so much for the help. --- you can't be what you were...so you better start being just what you are....

        your code example is correct. ?: is called the ternary operator. you can read about it in perlop

        ~Particle *accelerates*

Re: Filling In "The Gaps" in an Array
by BrowserUk (Patriarch) on Dec 11, 2002 at 23:51 UTC

    I'm not sure if I understood your post or your code, but I think this does what you wanted.

    #!/usr/bin/perl -w use strict; my @IDS; my $last = [0,0,0,0,0]; # In case the first line has fields missing while (<DATA>) { my @temp = split/\t+/; # allow multiple tab seperators. # set this element from the last if it's null $temp[$_] eq '' and $temp[$_] = $last->[$_] for 0 .. $#temp; push @IDS, $last = \@temp; # push saving a reference } print "@{$_}" for @IDS; =pod output c:\test>219201 1234 5 20021201 1 0 5678 0 20021202 0 0 5678 0 0 0 10 9120 10 20021211 0 0 6543 5 20021202 0 0 6543 0 0 0 5 6543 0 0 0 5 =cut __END__ 1234 5 20021201 1 0 5678 0 20021202 0 0 0 0 0 10 9120 10 20021211 0 0 6543 5 20021202 0 0 0 0 0 5 0 0 0 5

    Okay you lot, get your wings on the left, halos on the right. It's one size fits all, and "No!", you can't have a different color.
    Pick up your cloud down the end and "Yes" if you get allocated a grey one they are a bit damp under foot, but someone has to get them.
    Get used to the wings fast cos its an 8 hour day...unless the Govenor calls for a cyclone or hurricane, in which case 16 hour shifts are mandatory.
    Just be grateful that you arrived just as the tornado season finished. Them buggers are real work.

      I don't think that multiple-tab delimiters are allowed by the problem as stated. If they were, how could you skip a field in the middle of a line? Also, you didn't allow for fields to be missing at the end of the line. Here is my attempt to fix the problems, with more test data showing the extra error conditions.
      #!/usr/bin/perl -w use strict; my @IDS; my $rowlen = 5; my $last = [(0) x $rowlen]; # In case the first line has fields missin +g while (<DATA>) { chomp; my @temp = split/\t/,$_; # set this element from the last if it's null (!defined($temp[$_]) or $temp[$_] eq '') and $temp[$_] = $last->[$ +_] for 0 .. ($rowlen-1); push @IDS, $last = \@temp; # push saving a reference } print join("\t",@{$_}),"\n" for @IDS; =pod output % perl ddd.pl 0 0 0 0 0 1234 5 20021201 1 0 5678 0 20021202 1 0 5678 0 0 0 10 9120 10 20021211 0 0 6543 5 20021202 0 0 6543 0 0 0 5 6543 0 0 0 5 6543 0 0 0 5 =cut __END__ 1234 5 20021201 1 0 5678 0 20021202 0 0 0 10 9120 10 20021211 0 0 6543 5 20021202 0 0 0 5 0 0 0 5
        If you can assume that there will always be the same amount of tabs, you could write the split as:
        my @temp = split /\t/ => $_, -1;

        and @temp will then always contain the same amount of fields. If the third argument of split is negative, to trailing empty fields will be skipped.

        Abigail

        Good catch++


        Okay you lot, get your wings on the left, halos on the right. It's one size fits all, and "No!", you can't have a different color.
        Pick up your cloud down the end and "Yes" if you get allocated a grey one they are a bit damp under foot, but someone has to get them.
        Get used to the wings fast cos its an 8 hour day...unless the Govenor calls for a cyclone or hurricane, in which case 16 hour shifts are mandatory.
        Just be grateful that you arrived just as the tornado season finished. Them buggers are real work.