Link to home
Start Free TrialLog in
Avatar of mock5c
mock5c

asked on

Creating diagonal array but retaining first n columns.

This is sort of a continuation of  question I previously asked, which was:

https://www.experts-exchange.com/questions/21857321/combine-2D-arrays-in-a-funky-way.html

Please see the comments after the accepted answer posting.

An Expert provided this code:

for( \@ary1, \@ary2, \@ary3 ){
    my $right=@{$_->[0]};
    my $left=@combinedary&&@{$combinedary[0]};
    push @$_,(0)x$right for @combinedary;
    push @combinedary,[(0)x$left, @$_] for @$_;
}

The idea is to combined multiple arrays and create a "diagonal" of values and fill with zeros everywhere else, which is exactly what the above code accomplishes.  But for this question, I would like to retain the first n columns.  Please see below for a detailed description.  This example only combines two arrays but the solution should apply to two or more arrays.

@ary1 = (
[1,2,3,4]
);

@ary2 = (
[10,9,8]
);

If n==2, then the final array would be:
@final = (
[1,2,3,4,0],
[10,9,0,0,8]
),

if n==1, then the final array would be:
@final = (
[1,2,3,4,0,0],
[10,0,0,0,9,8]
);

Another way to think of this would be to add @ary1 and @ary2:

@combined = (
[1,2,3,4],
[10,9,8]
);

Then split after n columns:
n==2:
@left = (
[1,2],
[10,9]
);

@right = (
[3,4],
[8]
);

Apply the above zero padding method to @right but leave @left alone:
@right_result = (
[3,4,0],
[0,0,8]
);

Finally, put @left and @right_result together:
@rightleft = (
[1,2,3,4,0]
[10,9,0,0,8]
);
Avatar of Adam314
Adam314

For the zero padding, You want the first array to have all padding to the right, the each array after that to have padding to the left such that it's 3rd (if n=2) element is 1 column after the last elemnt of the previous array?

Building on the code from before:




#!/usr/bin/perl
use strict;
use Data::Dumper;

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

my @ary2 = (
[10,9,8]
);

#Combine arrays.  First argument is number of elements to keep, remaining arguments are pointers to arrays
my @arrfinal=Combine(2,\@ary1, \@ary2);
print Dumper(\@arrfinal);

#This subroutine will combine all arrays passed to it
sub Combine {
      my ($NumToKeep,@ArrPtr)=@_;
      my (@left,@combinedary);
      
      #Create left, the remaining is right
      foreach my $arr (@ArrPtr){
            #push @left, [];
            foreach my $row (@{$arr}){
                  push @left, [];
                  #push @{$left[-1]}, [];
                  #push @{${$left[-1]}[-1]}, shift @{$row} for (1..$NumToKeep);
                  push @{$left[-1]}, shift @{$row} for (1..$NumToKeep);
            }
      }
      
      #This is the same code from before
      for( @ArrPtr ){
          my $right=@{$_->[0]};
          my $left=@combinedary&&@{$combinedary[0]};
          push @$_,(0)x$right for @combinedary;
          push @combinedary,[(0)x$left, @$_] for @$_;
      }
      
      #Combine the two arrays
      foreach my $row (@left){
            my $combrow=shift @combinedary;
            push @$row, shift @{$combrow} while $#{$combrow}>=0;
      }
      return @left;
}

Some lines are commented out... you can delete those - they were there for debugging
ASKER CERTIFIED SOLUTION
Avatar of ozo
ozo
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial