http://www.perlmonks.org?node_id=11105908

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

I currently set a variable to hold a column-measuring scale from 1 to 220. It is set as a string literal and works fine, but every time I look at it I keep thinking there must be a more compact (and perlish) way to do it. The following code is my first attempt. It loads the value statically to the variable "$old" (for comparison while testing), then loads the value programmatically to the variable "$new". It "works", but there are still lots of numeric literals floating around in there. I say it is now "semi-static" instead of totally static, but I'm sure it can be done better. Can anyone come up with a more generic way of generating this value? TIA.

#!/usr/bin/perl use strict; use warnings; my $old = '|---+----10---+----20---+----30---+----40---+----50---+---- +60---+----70---+----80---+----90---+----100--+----10---+----20---+--- +-30---+----40---+----50---+----60---+----70---+----80---+----90---+-- +--200--+----10---+----20---+----'; my $new = '|---+----'; # Set base value starting with vertical bar. for (my $i = 10; $i <= 220; $i+=10) { my $j = $i; $j = $i-200 if $i > 200 && $i < 300; # Change '210' to '10', '220 +' to '20', etc. $j = $i-100 if $i > 100 && $i < 200; # Change '110' to '10', '120 +' to '20', etc. my $filler = $i == 100 || $i == 200 ? '--+----' : '---+----'; # A +djust filler for 3-digit number. $new .= $j . $filler; } print "\nold=$old\n\nnew=$new\n";

"It's not how hard you work, it's how much you get done."

  • Comment on How to build a better mousetrap (or a variable to hold a column-measuring scale)
  • Download Code

Replies are listed 'Best First'.
Re: How to build a better mousetrap (or a variable to hold a column-measuring scale)
by Paladin (Vicar) on Sep 09, 2019 at 20:52 UTC
    How about something like:
    #!/usr/bin/perl use strict; use warnings; my $len = $ARGV[0]; my $cur = 10; print "|---+----"; while ($cur < $len) { my $prn = $cur % 100 ? $cur % 100 : $cur; my $sep = substr "|----+----", length($prn); print $prn, $sep; $cur += 10; } print "|\n";
    No hardcoded numbers at all. Call it with prog.pl <length>:
    ~/tmp$ perl ruler.pl 50
    |---+----10---+----20---+----30---+----40---+----|
    ~/tmp$ perl ruler.pl 140
    |---+----10---+----20---+----30---+----40---+----50---+----60---+----70---+----80---+----90---+----100--+----10---+----20---+----30---+----|
    
Re: How to build a better mousetrap (or a variable to hold a column-measuring scale)
by LanX (Archbishop) on Sep 09, 2019 at 21:09 UTC
    does this help?
    DB<82> p join "+", map { $b =$_ %10; $a = sprintf "----%s--", $b ? " +${b}0-" : "${_}0" } 8..12 ----80---+----90---+----100--+----10---+----20---

    could be shorter but I'm tired! ;-)

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: How to build a better mousetrap (or a variable to hold a column-measuring scale)
by atcroft (Abbot) on Sep 09, 2019 at 21:20 UTC

    My current way of generating such an on-screen ruler is that I display position digits for the 100s, 10s, and 1s places vertically on (n % 5) except for the 1s place, where I display a pipe ('|') on (n % 10), a plus ('+') on (n % 5), or the value of (n % 10) otherwise. (Whitespace added to improve readability in <code> segment.)

    perl -le ' my $n = shift @ARGV; $n = 80 unless ( defined $n ); my @place; foreach + my $i ( 1 .. $n ) { $place[2] .= ( ( $i >= 100 and ! ($i % 5) ) ? +int( $i / 100 ) % 10 : q{ } ); $place[1] .= ( ( $i >= 10 and ! ( $i % + 5 ) ) ? int( $i / 10 ) % 10 : q{ } ); $place[0] .= ( ! ( $i % 10 ) ? + q{|} : ( ! ( $i % 5 ) ? q{+} : $i % 10 ) ); } foreach my $s ( + reverse @place ) { print $s; }' 60
    And example output (for width 60):
    1 1 2 2 3 3 4 4 5 5 6 1234+6789|1234+6789|1234+6789|1234+6789|1234+6789|1234+6789|

    Hope that helps.

Re: How to build a better mousetrap (or a variable to hold a column-measuring scale)
by shmem (Chancellor) on Sep 10, 2019 at 14:19 UTC

    join map sprintf:

    use 5.10.0; $_=join"+",map{$n=$_*10;sprintf" %-5s",$n%100||$n}1..22; s/ /-/g; # replace blanks with dashes s/-/|/; # make first dash into a pipe sign $_.='|'; # add pipe sign to the end say; __END__ |---10---+----20---+----30---+----40---+----50---+----60---+----70---+ +----80---+----90---+----100--+----10---+----20---+----30---+----40--- ++----50---+----60---+----70---+----80---+----90---+----200--+----10-- +-+----20---|
    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
      Thank you shmem. I think this is the one I will go with. I tweaked your entry a little to get the first 5 characters right.
      use 5.10.0; $_=join"+",map{my $n=$_*10;sprintf" %-5s",$n%100||$n}1..22; s/ /| + /; # make first blank a pipe sign s/ /-/g; # replace blanks with dashes $_.='|'; # add pipe sign to the end say; __END__

      "It's not how hard you work, it's how much you get done."

Re: How to build a better mousetrap (or a variable to hold a column-measuring scale)
by LanX (Archbishop) on Sep 09, 2019 at 23:13 UTC
    more ways to do it, more generic :)
    DB<111> $p = '|----+----' DB<112> p map { $a=$p; substr $a,0,length($_),$_ ;$a} "", map {$b=$_ +%10; $b ? $b*10 :$_*10 } 1..22 |----+----10---+----20---+----30---+----40---+----50---+----60---+---- +70---+----80---+----90---+----100--+----10---+----20---+----30---+--- +-40---+----50---+----60---+----70---+----80---+----90---+----200--+-- +--10---+----20---+---- DB<113> p map { $a=$p; substr $a,0,length($_),$_ ;$a} "",map $_*10, +map {1..9, $_*10} 1..2 |----+----10---+----20---+----30---+----40---+----50---+----60---+---- +70---+----80---+----90---+----100--+----10---+----20---+----30---+--- +-40---+----50---+----60---+----70---+----80---+----90---+----200--+-- +-- DB<121> p map { $a=length; $p =~ s/.{$a}/$_/r} "", map {$b=$_%10; $b + ? $b*10 :$_*10 } 1..22 |----+----10---+----20---+----30---+----40---+----50---+----60---+---- +70---+----80---+----90---+----100--+----10---+----20---+----30---+--- +-40---+----50---+----60---+----70---+----80---+----90---+----200--+-- +--10---+----20---+----

    update

    the initial pattern is buggy, replacing $p = '|---+----' would fix it.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: How to build a better mousetrap (or a variable to hold a column-measuring scale)
by AnomalousMonk (Bishop) on Sep 10, 2019 at 01:09 UTC

    Sorry for the wrap-around.

    c:\@Work\Perl\monks>perl -wMstrict -le "my $old = '|---+----10---+----20---+----30---+----40---+----50---+----60---+- +---70---+----80---+----90---+----100--+----10---+- ---20---+----30---+----40---+----50---+----60---+----70---+----80---+- +---90---+----200--+----10---+----20---+----'; print qq{>$old<}; ;; my $fill = '--+----'; ;; my $new = qq{|-$fill}; $new .= grad($_*10) . $fill for 1 .. 22; die 'nope' unless $new eq $old; print qq{>$new<}; ;; sub grad { return $_[0] % 100 ? $_[0]%100 . '-' : $_[0]; } " >|---+----10---+----20---+----30---+----40---+----50---+----60---+---- +70---+----80---+----90---+----100--+----10---+---- 20---+----30---+----40---+----50---+----60---+----70---+----80---+---- +90---+----200--+----10---+----20---+----< >|---+----10---+----20---+----30---+----40---+----50---+----60---+---- +70---+----80---+----90---+----100--+----10---+---- 20---+----30---+----40---+----50---+----60---+----70---+----80---+---- +90---+----200--+----10---+----20---+----<


    Give a man a fish:  <%-{-{-{-<

Re: How to build a better mousetrap (or a variable to hold a column-measuring scale)
by rsFalse (Hermit) on Sep 10, 2019 at 12:39 UTC
    This left-justified variant:
    #!/usr/bin/perl -l # https://www.perlmonks.org/?node_id=11105908 use strict; use warnings; my $len = $ARGV[0]; my $new = '----+----|'; $_ = $new x $len; my $i = 0; my $ii; s/ \| (??{ $i += 10; $ii = $i =~ s!.*(?=[^0])!!r; quotemeta '-' x ( -1 + length $ii ); }) / $ii /gex; s/./|/; print;
    Output:
    |---+----10---+----20---+----30---+----40---+----50---+----60---+----7 +0---+----80---+----90---+----100--+----10---+----20---+----30---+---- +40---+----50---+----60---+----70---+----80---+----90---+----200--+--- +-10---+----20---+----|
    This right-justified variant:
    #!/usr/bin/perl -l # https://www.perlmonks.org/?node_id=11105908 use strict; use warnings; my $len = $ARGV[0]; my $new = '----+----0'; $_ = $new x $len; my $i = 0; my $space = '-' x 4; my $space_quotemeta = quotemeta $space; s/ $space_quotemeta (?= 0 ) / $i ++; my $ii = $i =~ s!.*(?=[^0])!!r; $space =~ s! (??{ quotemeta '-' x length $ii }) $ !$ii!xr; /gex; s/./|/; print;
    Output:
    |---+---10----+---20----+---30----+---40----+---50----+---60----+---70 +----+---80----+---90----+--100----+---10----+---20----+---30----+---4 +0----+---50----+---60----+---70----+---80----+---90----+--200----+--- +10----+---20----+---30
    Input was '23'.
Re: How to build a better mousetrap (or a variable to hold a column-measuring scale)
by roho (Chancellor) on Sep 10, 2019 at 10:49 UTC
    Thank you all for your replies. Lots of great ideas and approaches. TMTOWTDI at its finest.

    "It's not how hard you work, it's how much you get done."