Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

How to build a better mousetrap (or a variable to hold a column-measuring scale)

by roho (Canon)
on Sep 09, 2019 at 16:26 UTC ( #11105908=perlquestion: print w/replies, xml ) Need Help??

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 16: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 17: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 17: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 10: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 19: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 09, 2019 at 21: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 (Friar) on Sep 10, 2019 at 08: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 (Canon) on Sep 10, 2019 at 06: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."

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://11105908]
Approved by Paladin
Front-paged by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (8)
As of 2019-09-17 10:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    The room is dark, and your next move is ...












    Results (206 votes). Check out past polls.

    Notices?