KGee
KGee

Reputation: 373

How to find the horizontal absolute value in perl

I have this code

if (@row1) {
            die "Bad format!" if @row1 != @row2;
            my @new = map { abs ($row2[$_] - $row1[$_]) } 0..$#row2;

which is resulting the absolute value of row2 -row1.

I tried instead of the abs (row2-row1) to find the absolute value of element 2 -element 1 of the same line of each of all the line, in continuity of upper code. My goal is to obtain the abs(row2 -row1) --> from the new values --> second element -first element of the same line for all the lines.

1 2 3 4

1 4 3 4

1 5 2 3

to become

0 2 0 0

0 1 1 1

which is already done and then to have the final output

2 2 0

1 0 1

So I edited the upper code to:

 for ($i=1,$i++,$i>$row){
   my @new1 = map { abs ($row1[$2+$i] - $row1[$1+$i]) } 0..$#row1;
              say join " ", @new1;}

but I got "Use of uninitialized value $i in addition". I also substitute $i with "my$i" as well as with "i" and go the same errors. Could someone can explain to me why what I'm trying is wrong?

Upvotes: 1

Views: 196

Answers (3)

Polar Bear
Polar Bear

Reputation: 6798

OP's question is not very clear what he wants to do with the data.

My understanding is that he would like to apply vertical and horizontal abs diff recursively.

To simplify processing code, two subroutines was implemented abs_vdiff and abs_hdiff.

#!/usr/bin/perl
#
# USAGE:
#   prog.pl
#
# Description:
#   Demonstration code for StackOverflow Q59945359
#
# StackOverflow: 
#   Question 59945359
#
# Author:
#   Polar Bear
#
# Date: Tue Jan 28 13:35:00 PST 2020
#

use strict;
use warnings;
use feature 'say';

my $array = read_array();
my $vdiff = abs_vdiff($array);
my $hdiff = abs_hdiff($vdiff);

say "Read array";
show($array);
say "ABS vertical diff";
show($vdiff);
say "ABS horizontal diff";
show($hdiff);
say "We done";

sub read_array {
    my @data;

    while( <DATA> ) {
        my @row = split ' ';
        push @data, \@row;
    }

    return \@data;
}

sub abs_vdiff {
    my $array = shift;
    my @result;

    foreach my $i ( 1..$#{$array} ) {
        my @data = map { abs(@{@{$array}[$i]}[$_]-@{@{$array}[$i-1]}[$_]) } 0..$#{@{$array}[$i]};
        push @result, \@data;
    }
    return \@result;
}

sub abs_hdiff {
    my $array = shift;
    my @data;

    foreach my $row (@{$array}) {
        my @row = map { abs(@{$row}[$_]-@{$row}[$_+1]) } 0..$#{$row}-1;
        push @data, \@row;
    }

    return \@data;
}

sub show {
    my $array = shift;

    foreach my $row ( @{$array} ) {
        say join ' ', @{$row};
    }
}

__DATA__
1 2 3 4
1 4 3 4
1 5 2 3

Output

Read array
1 2 3 4
1 4 3 4
1 5 2 3
ABS vertical diff
0 2 0 0
0 1 1 1
ABS horizontal diff
2 2 0
1 0 0
We done

Upvotes: 0

Polar Bear
Polar Bear

Reputation: 6798

One of many possible solutions to the problem

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

my $debug = 0;      # debug flag

my $flag = 1;
my @current;
my @previous;
my @final;

say "First stage";

while( <DATA> ) {
    @current = split ' ';
    if( $flag ) {
        @previous = @current;
        $flag = 0;
        next;
    }
    if( $#current != $#previous ) {
        say "Ops, lines have different number of elements";
        say "Previous: " . join ' ', @previous;
        say "Current: "  . join ' ', @current;
    } else {
        my @data = map { abs($current[$_]-$previous[$_]) } 0..$#current;
        say join ' ', @data;
        push @final, \@data;
    }
    @previous = @current;
}

print Dumper(\@final) if $debug;

say "Second stage";

foreach my $row (@final) {
    my @data = map { abs(@{$row}[$_]-@{$row}[$_+1]) } 0..$#{$row}-1;
    say join ' ', @data;
}

__DATA__
1 2 3 4
1 4 3 4
1 5 2 3

Output

First stage
0 2 0 0
0 1 1 1
Second stage
2 2 0
1 0 0

Upvotes: 0

ikegami
ikegami

Reputation: 386331

my @rows = (
   [ 1, 2, 3, 4 ],
   [ 1, 4, 3, 4 ],
   [ 1, 5, 2, 3 ],
);

my $num_cols = @{ $rows[0] };

for my $r (1..$#rows) {
   die "Bad format!" if @{ $rows[$r] } != $num_cols;

   my @diffs = map { abs($rows[$r-1][$_] - $rows[$r][$_]) } 0..$num_cols-1;
   my @diff_diffs = map { abs($diffs[$_-1] - $diffs[$_]) } 1..$num_cols-1;
   say "@diff_diffs";
}

Upvotes: 2

Related Questions