I personally believe that a nice example can be found in some code (link @ GG) I posted in clpmisc some time ago.
(Minimal) premise:
On Fri, 05 Oct 2007 16:49:31 -0500, "Mumia W." <paduille.4061.mumia.w+nospam@earthlink.net> wrote: >I know the mean can be calculated "on the fly"--without storing all o +f >the values to be examined, but I can't see how this is to be done wit +h >the median; I don't think it's possible. Sure it is possible:
Code:
#!/usr/bin/perl use strict; use warnings; use List::Util 'sum'; use constant TESTS => 20; use Test::More tests => TESTS; sub naive { my @arr = map +($_) x $_[$_], 0..$#_; @arr % 2 ? @arr[(@arr-1)/2] : (@arr[@arr/2 - 1] + @arr[@arr/2])/2; } sub findidx { my $i=shift; ($i -= $_[$_])<0 and return $_ for 0..$#_; } sub smart { my $t=sum @_; $t%2 ? findidx +($t-1)/2, @_ : (findidx($t/2-1, @_) + findidx($t/2, @_))/2; } for (1..TESTS) { my @a=map int rand 10, 0..5; is smart(@a), naive(@a), "Test @a"; } __END__
Here, if I were not to have findidx() as a separate sub but inline its code/logic into smart(), I would probably do it like thus:
sub smart { my $t=sum @_; if ($t%2) { my $i=($t-1)/2; ($i -= $_[$_])<0 and return $_ for 0..$#_; } else { my $i=$t/2-1; my ($found1, $found2); for (0..$#_) { ($found1=$_), last if ($i -= $_[$_])<0; } my $j=$t/2; for (0..$#_) { ($found2=$_), last if ($j -= $_[$_])<0; } return ($found1+$found2)/2; } }
Of course there are other WTDI as usual, however one cannot but notice that in this particular case not only did factoring code away in a sub reduce duplication, but it even gave one the possibility of applying some syntactic sugar that makes code overall more terse and clear.
Note: I had and still have the overall impression that when in smart() it happens that t%2 == 0, one could avoid basically doing twice the same loop - but I had tried one or two approaches that seemed obvious to me, and they failed. I posted the code as is seen above because mine was a proof of concept anyway. I guess something subtle and simple (a posteriori) is baffling me. Of course, this is a whole another story...
Update: the twin for loops look really awful - thus YAWTDI for smart() that I would probably favour is:
sub smart { my $t=sum @_; if ($t%2) { my $i=($t-1)/2; ($i -= $_[$_])<0 and return $_ for 0..$#_; } else { my $acc=0; for my $i ($t/2-1, $t/2) { for (0..$#_) { ($acc += $_), last if ($i -= $_[$_])<0; } } return $acc/2; } }
Update: switched from spoiler tags around the minimal description to readmore at Argel's request.
In reply to Re^2: when to use subroutine
by blazar
in thread when to use subroutine
by convenientstore
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |