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

I have data (the data itself is irrelevant) that I want to spread across columns. In explaination, what I want to do is spread the data so that, for example if there is 19 pieces of data, and I want 5 columns of it, it will spread it as 4-4-4-4-3, if I have 27, it will spread it as 6-6-6-6-3, and so forth. I want it to make it evenly spread out, with the remainder in the last column, but I have no idea how to do any of this, let alone where to start.

Any help that could be offered would be greatly appriciated.
“A script is what you give the actors. A program is what you give the audience.” ~ Larry Wall

Replies are listed 'Best First'.
Re: Even column spreading of data
by tachyon (Chancellor) on Dec 22, 2002 at 02:58 UTC

    Here is a generic solution that returns a reference to an array of arrays. You can then output that formatted any way you want. For example if you wanted HTML table rows you could use print '<tr>' . (join '', map { "<td>$_</td>" } @cols) . "</tr>\n";

    my @data = 11 .. 42; my $cols = 7; my $ref = get_cols( $cols, \@data ); # display the data for my $row ( @$ref ) { my @cols = @$row; print "@cols\n"; } sub get_cols { my ( $cols, $data_ref ) = @_; my $count = 0; my @ary; for my $item ( @$data_ref ) { $count++ % $cols ? push @{$ary[-1]}, $item : push @ary, [$item +]; } return \@ary; } __DATA__ 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Even column spreading of data
by pg (Canon) on Dec 22, 2002 at 01:27 UTC
    Another solution
    sub spread { return ($_[0] % $_[1])?join("-", ((int($_[0] / ($_[1] - 1))) x ($_ +[1]-1), ($_[0] % ($_[1] - 1)))):join("-", (int($_[0] / $_[1])) x $_[1 +]); } print spread(19,4); #test first branch of ?: print spread(25,5); #test second branch of ?:
    Update: I read FamousLongAgo's reply, and thanks for testing my code.

    However I don't think there is any problem, although in the 22/7 case, that 4 in the last column is greater than 3's in the rest columns. This really depends on how you define "evenly", and what "remainder goes to last column" means.

    My understanding is that other than the last column, other columns should be exactly the same; Whatever left goes to last column. It is never said anywhere in his post, that the last column cannot be greater than the rest.

    However the value of the last column must be less than $col - 1 (number of columns - 1), if it is greater than or equals to "number of columns - 1", then it is really not even, and you really should redistribute.

    As for whether the code is reable, I don't think it is too difficult to understand, as obviously you understood, and tried to reformat it, but this is more perlier ;-)
      Same code ( what is this, Lisp? ), reformatted to be more readable and do a sanity check for the zero-columns case. Note that it doesn't seem to do exactly what the questioner asked - see the 22/7 case:
      #!/usr/bin/perl -w use strict; while (<DATA> ) { my ( $items, $cols ) = split; print "Spread for $items, $cols = ", spread( $items, $cols ), "\n"; } sub spread { my ($a, $cols) = @_; $a ||= 0; return unless $cols > 0; # avoid nasty surprises return $a if $cols == 1; #trivial case if ( $a % $cols) { return join '-', ( (int( $a / ($cols - 1) )) x ( $cols - 1) +, ( $a % ($cols - 1))); } else { return join '-', (int ( $a / $cols)) x $cols; } } __DATA__ 19 3 20 5 22 7 2 47 0 9 899 0
      Results:
      Spread for 19, 3 = 9-9-1 Spread for 20, 5 = 4-4-4-4-4 Spread for 22, 7 = 3-3-3-3-3-3-4 Spread for 2, 47 = 0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0 +-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-2 Spread for 0, 9 = 0-0-0-0-0-0-0-0-0 Spread for 899, 0 =
      I'm not sure of any way I can explain what I mean any further than I did. Basically, what I want is the first (Columns_Number - 1) columns to have the same number of digits in them, and the last column will have the remainder, which would be <= the total number to spread. The only real easy way I can think of to explain it would be an example of a total of 19, spread over 5 columns, which would turn out as 4-4-4-4-3.

      That is going to be as best I can possibly explain "evenly" and "remainder goes to last column" in my own words. Sorry if this leaves any gaping holes in my request. =/
      “A script is what you give the actors. A program is what you give the audience.” ~ Larry Wall
Re: Even column spreading of data
by Beatnik (Parson) on Dec 22, 2002 at 00:53 UTC
    $items_per_column = 5; @items = qw(aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm); $counter = 0; for(@items) { print $_,"\t"; $counter++; if ($counter == $items_per_co +lumn) { $counter = 0; print "\n"; } }
    or something like that

    Greetz
    Beatnik
    ...Perl is like sex: if you're doing it wrong, there's no fun to it.
Re: Even column spreading of data
by Anonymous Monk on Dec 22, 2002 at 11:18 UTC
    I read this as wanting the data spread in columns each with an equal number of rows (except the last column which has the remainder) - like columns of words on a magazine page. If this is correct, I offer the following ;
    use strict; use warnings; my @data = 1 .. 99; my $cols = 6 ; my $items = $#data + 1; my $rows = int ($items / $cols); $rows += 1 if ($items % $cols); for my $r (1..$rows){ for my $c (1..$cols){ my $i = ($r - 1) + ($c - 1) * $rows; print $data[$i]."\t"; } print "\n"; }
      Your code, as simple as it may be, worked as one of the best, except for one fatal flaw. Often times, when I would do different variations of items and columns, which would return maybe 1 or 0 as the final column's amount of items, it would throw a wrench into the entire assembly. Another instance was when I would try things such as FamousLongAgo did, such as doing erroristic combinations of like 99 rows of 2 items, or 0 rows of 99 items. Not saying I need these precautions, but you never know where being safe may help in appliance.
      “A script is what you give the actors. A program is what you give the audience.” ~ Larry Wall
Re: Even column spreading of data
by Kage (Scribe) on Dec 22, 2002 at 00:36 UTC
    I forgot to add that I also want it to work with different column numbers, such as 5, 4, 6, and any others.
    “A script is what you give the actors. A program is what you give the audience.” ~ Larry Wall