Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clean way to split an array into thirds and display to user

Tags:

arrays

perl

I have a sorted array in a perl script eg:

qw(aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll)

Is there an easy way to display it in three columns so that

  1. first third is in left column
  2. middle third is in middle column
  3. and last third is in right column

This is so the elements can be displayed running down the screen instead of across it. eg

aaa eee iii
bbb fff jjj
ccc ggg kkk
ddd hhh lll

I have been trying to use modulus but it's getting complicated and thought there might be an elegant solution. Ultimately I intend to use it for something similar to select in bash.

Thank you.

like image 546
David Avatar asked Oct 17 '13 02:10

David


4 Answers

use List::MoreUtils qw( part );
my $num_rows = int(@a/3);
my @aoa = map [ @a[@$_] ], part { $_ % $num_rows } 0..$#a;
print("@$_\n") for @aoa;

or

use List::MoreUtils qw( part );
my $num_rows = int(@a/3);
my @aoa = part { $_ % $num_rows } 0..$#a;
print("@a[ @$_ ]\n") for @aoa;

or

my $num_rows = int(@a/3);
for my $row_num (0..$num_rows-1) {
   print("@a[ map { $row_num + $num_rows*$_ } 0..2 ]\n");
}

Versions of the above that don't assumes @a % 3 == 0.

use List::MoreUtils qw( part );
use POSIX           qw( ceil );
my $num_rows = ceil(@a/3);
my @aoa = map [ @a[@$_] ], part { $_ % $num_rows } 0..$#a;
print("@$_\n") for @aoa;

or

use List::MoreUtils qw( part );
use POSIX           qw( ceil );
my $num_rows = ceil(@a/3);
my @aoa = part { $_ % $num_rows } 0..$#a;
print("@a[ @$_ ]\n") for @aoa;

or

use POSIX qw( ceil );
my $num_rows = ceil(@a/3);
for my $row_num (0..$num_rows-1) {
   print("@a[ grep { $_ < @a } map { $row_num + $num_rows*$_ } 0..2 ]\n");
}
like image 116
ikegami Avatar answered Oct 29 '22 16:10

ikegami


After reading this question, it looked a lot like an example that I read in the docs for Perl6::Form. ( Which is the Perl5 implementation )

use strict;
use warnings;
use Perl6::Form;

my @array = qw'aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll';

print form
  "{[[[[[:} {:[[[[:} {:[[[[[}",
  \@array,  \@array, \@array;
aaa      eee      iii
bbb      fff      jjj
ccc      ggg      kkk
ddd      hhh      lll

It won't work like you want it to, if any of the strings is longer than has been allotted for it.

...
$array[-1] .= ' lllllll';
...
aaa      fff      kkk
bbb      ggg      lll
ccc      hhh      lllllll
ddd      iii
eee      jjj

Of course you could calculate the required width before the call to form.

...

use List::Util qw'max';

my $max_length = max 5, map length, @array; # at least 5
my $TERMINAL_WIDTH = 80;
my $number_of_cols = int( $TERMINAL_WIDTH / ($max_length+1) );

my $single = '{:' . ( '[' x ($max_length-4) ) . ':} ';

print $single, "\n\n"; # debug statement

print form
  $single x $number_of_cols,
  (\@array) x $number_of_cols;
{:[[[[[[[:}

aaa         ccc         eee         ggg         iii         kkk
bbb         ddd         fff         hhh         jjj         lll lllllll
                                                                            80 ^
like image 28
Brad Gilbert Avatar answered Oct 29 '22 16:10

Brad Gilbert


Here is my solution, hope it helps you.

use strict;
use warnings;

my @arr = ("aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "lll");
my $size = @arr;

my $column = 3;

my $mod = $size / $column;

my $i = $size;
my $count = 0;
while ($i > 0) {
    my $k = $count;
    while ($k < $size) {
        print "$arr[$k]\t";
        $k += $mod;
    }
    print "\n";
    $count++;
    $i -= $column;
}
like image 32
lightbringer Avatar answered Oct 29 '22 16:10

lightbringer


my @foo = qw(aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll);
my $rows = int( (@foo+2) / 3 );
my @row;
$row[$_ % $rows][$_ / $rows] = $foo[$_] for 0..$#foo;
for my $row (@row) {
    print join(' ', @$row), "\n";
}
like image 37
ysth Avatar answered Oct 29 '22 16:10

ysth