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

Dear members, I have a text file with numbers which I have grouped as follows, seperated by blank line:
42.034 41.630 40.158 26.823 26.366 25.289 23.949 34.712 35.133 35.185 35.577 28.463 28.412 30.831 33.490 33.839 32.059 32.072 33.425 33.349 34.709 <\code> the groups are always of equal length and can be arranged in more than + one line long, (if the group is large, say 500 numbers long); sepera +ted by blank lines ! My question is: how should I subtract the first element of array 2 fro +m array 1, array 3 from array 2, similarly for the second element and + so on till the end of the group? i.e.: 34.712-42.034,35.133-41.630,35.185-40.158 ...till the end of each grou +p 33.490-34.712,33.839-35.133 .................. I did use pairwise , use List::MoreUtils qw<pairwise>; But i am unable to assign them into array correctly <code> while (<IN>){ my @list1 = split ' ', <IN>; my @list2 = split ' ', <IN>; my @diff = pairwise { $b - $a } @list2, @list1; }
@list2 always ends up containing nothing ! Please give me some suggestions Thanks, Sidac

Replies are listed 'Best First'.
Re: subtraction in array
by roboticus (Chancellor) on Mar 02, 2011 at 14:46 UTC

    Sidac:

    You can tell perl to read entire records at a time by setting the input record separator to a blank line (see perlvar). Then you can split the record on whitespace, like so:

    $ cat t.pl #!/usr/bin/perl use strict; use warnings; use List::MoreUtils qw<pairwise>; $/=""; my @list1 = split /\s+/, <DATA>; my @list2 = split /\s+/, <DATA>; my @diff = pairwise { $b-$a } @list2, @list1; print join(", ", @diff),"\n"; __DATA__ 42.034 41.630 40.158 26.823 26.366 25.289 23.949 34.712 35.133 35.185 35.577 28.463 28.412 30.831 $ perl t.pl Name "main::b" used only once: possible typo at t.pl line 9. Name "main::a" used only once: possible typo at t.pl line 9. 7.322, 6.497, 4.973, -8.754, -2.097, -3.123, -6.882

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: subtraction in array
by toolic (Bishop) on Mar 02, 2011 at 14:29 UTC
    use warnings; use strict; use Data::Dumper; my @list1; my @list2; while (<DATA>) { next unless /\S/; @list1 = split; if (@list2) { my @diff; for my $i (0 .. $#list1) { push @diff, ($list1[$i] - $list2[$i]); } print Dumper(\@diff); } @list2 = @list1; } __DATA__ 42.034 41.630 40.158 26.823 26.366 25.289 23.949 34.712 35.133 35.185 35.577 28.463 28.412 30.831 33.490 33.839 32.059 32.072 33.425 33.349 34.709
    prints:
    $VAR1 = [ '-7.322', '-6.497', '-4.973', '8.754', '2.097', '3.123', '6.882' ]; $VAR1 = [ '-1.222', '-1.294', '-3.126', '-3.505', '4.962', '4.937', '3.878' ];
Re: subtraction in array
by SuicideJunkie (Vicar) on Mar 02, 2011 at 14:24 UTC

    What's the difference between <IN> and <$file_handle>? Did you copy and paste that directly from your code or are there typos?

    If you're reading one line at a time, and every other line in your file is blank, it only makes sense that your second read will get you no numbers...

    You could add more prints to your code, throw in some temporary variables so you can print what you've read from the file before you try to split it. I'd suggest a print inside your pairwise block as well; based on a quick look at pairwise's examples, it does not take two lists as parameters, just one.

Re: subtraction in array
by umasuresh (Hermit) on Mar 02, 2011 at 14:23 UTC
    If I understand your question correctly:
    use strict; use warnings; use List::MoreUtils qw<pairwise>; my @previous; my $i =0; LINE:while (<DATA>) { $i++; my $line = $_; my @current = split ' ', $line; my @diff; if($i ==1) { @previous = split ' ', $line; next LINE; } else { @diff = pairwise { $b - $a } @previous, @current; } @previous = split ' ', $line; print join(" ", @diff); print "\n"; } __DATA__ 42.034 41.630 40.158 26.823 26.366 25.289 23.949 34.712 35.133 35.185 35.577 28.463 28.412 30.831 33.490 33.839 32.059 32.072 33.425 33.349 34.709
Re: subtraction in array
by Marshall (Canon) on Mar 02, 2011 at 21:04 UTC
    This code is just not going to work... @list = <IN>; #slurps whole into @list Your code:
    while (<IN>) { my @list1 = split ' ', <IN>; my @list2 = split ' ', <IN>; my @diff = pairwise { $b - $a } @list2, @list1; }
    Why would you think that @list1 and @list2 would have alternating lines? Curious minds would like to know what your thinking was in this code? Once you have read <IN>, what makes you think that you can do it again in the list2 assignment? <IN> is now "empty".

    User input, like disk file input can only be read once without asking the user or the disk to Please "read it again for me". -----------------------------

    If I understood your requirement correctly, this is a straight-forward implementation.

    #!/usr/bin/perl -w use strict; use Data::Dumper; my @all_lines; my @this_record; ### parse the data ### while (<DATA>) { #chomp not needed as we are splitting on whitespace if (/^\d/) { push @this_record, split; } else #this is the blank line "separator", end-of-record { push @all_lines, [@this_record]; @this_record =(); } } push @all_lines, [@this_record]; # the last record at EOF ### print the result ### my $ref_current_line = $all_lines[0]; foreach my $ref_next_line (@all_lines[1..@all_lines-1]) { print "@$ref_current_line\n"; print "@$ref_next_line\n"; print "-----\n"; my @A = @$ref_current_line; my @B = @$ref_next_line; while ( (defined($a =shift @A) and defined( $b=shift @B)) ) { printf ("%6.3f ", $a-$b); } print "\n"; $ref_current_line = $ref_next_line; print "\n"; } =printout 42.034 41.630 40.158 26.823 26.366 25.289 23.949 34.712 35.133 35.185 35.577 28.463 28.412 30.831 ----- 7.322 6.497 4.973 -8.754 -2.097 -3.123 -6.882 34.712 35.133 35.185 35.577 28.463 28.412 30.831 33.490 33.839 32.059 32.072 33.425 33.349 34.709 ----- 1.222 1.294 3.126 3.505 -4.962 -4.937 -3.878 =cut __DATA__ 42.034 41.630 40.158 26.823 26.366 25.289 23.949 34.712 35.133 35.185 35.577 28.463 28.412 30.831 33.490 33.839 32.059 32.072 33.425 33.349 34.709