Re: A way to avoid repeated conditional loops
by tinita (Parson) on Aug 24, 2011 at 11:18 UTC
|
use the flip-flop operator.
if you want to read from alpha until end of file:
while (<$fh>) {
if ( (m/^alpha$/ .. eof($fh) ) > 1) {
# everything between alpha and end of file
}
}
you can even change that second condition to 0:
if ( (m/^alpha$/ .. 0 ) > 1) | [reply] [d/l] [select] |
|
|
| [reply] |
|
|
Are you assuming that 'alpha' is also always the first line in the file?
Also, the posted flipflop doesn't behave the same as the OP
A simpler way to just use a flag and short circuit the regex work:
my $seen = 0;
while (<$fh>)
{
if ( !$seen and m/^alpha$/)
{
$seen = 'yes indeed';
print "true\n";
}else{
print "false\n";
}
}
Given a test file of: foo
bar
alpha
beta
gamma
delta
The results I got are:Original:
false
false
true
false
false
false
Flipflop:
Argument "" isn't numeric in numeric gt (>) at test.pl line 21, <$fh>
+line 1.
false
Argument "" isn't numeric in numeric gt (>) at test.pl line 21, <$fh>
+line 2.
false
false
true
true
true
Flag:
false
false
true
false
false
false
| [reply] [d/l] [select] |
|
|
|
|
|
|
Re: A way to avoid repeated conditional loops
by AR (Friar) on Aug 24, 2011 at 10:37 UTC
|
...
while ( <FILE> ) {
if ( /alpha/ ) {
some code #1
last;
} else {
some code #2
}
}
while ( <FILE> ) {
some code #2
}
....
| [reply] [d/l] |
|
|
I wonder whether the copying of some code #2 is worth the avoidance of the test. Another way of writing it, with the same duplication:
while (<FILE>) {
if (/alpha/) {
some code #1;
while (<FILE>) {
some code #2;
}
}
else {
some code #2;
}
}
| [reply] [d/l] [select] |
|
|
OUTER: {
for (;;) {
defined( my $_ = <$fh> ) or last OUTER;
if (/alpha/) {
f();
last;
} else {
g();
}
}
while (<$fh>) {
g();
}
}
Update: The remainder of this post is wrong.
You can get rid of the duplicate g() by making the loops bottom tested.
OUTER: {
defined( my $_ = <$fh> ) or last OUTER;
for (;;) {
if (/alpha/) {
f();
last;
}
defined( $_ = <$fh> ) or last OUTER;
}
for (;;) {
g();
defined( $_ = <$fh> ) or last OUTER;
}
}
You can squish it down a bit:
LOOP: {
defined( my $_ = <$fh> ) or last;
if (/alpha/) {
f();
redo;
}
for (;;) {
g();
defined( $_ = <$fh> ) or last;
}
}
Look at that, g() is not even duplicated anymore!!
| [reply] [d/l] [select] |
|
|
| [reply] |
|
|
|
|
|
|
| [reply] |
|
|
|
|
|
|
If 'some code #2' is very small or can be packaged into a single function call, I might go with that. Or I might just make it obvious that we only want/expect this once in the one loop:
my $got_alpha;
while (<FILE>) {
unless ($got_alpha) {
if (/alpha/) {
#...alpha code
$got_alpha++;
next;
}
}
# ...more code
}
Update: And I just noticed the part in the OP where it says "without a flag variable"...oh, well...
| [reply] [d/l] |
|
|
| [reply] |
|
|
Interesting. I would never think of doing like this. Thanks :)
The only point, at first glance, would be that you get twice the "while" loop. I'm trying to understand if you can avoid such "ugly" (take the word for it) structures.
Thanks though.
| [reply] |
|
|
| [reply] |
Re: A way to avoid repeated conditional loops
by Eliya (Vicar) on Aug 24, 2011 at 19:37 UTC
|
Yet another way would be to set up a function(ref) which you just call for every line. Initially, the called function checks for /alpha/, but once alpha is encountered, it replaces itself with the routine do_beta that is then called directly for the remaining beta lines. That way, the condition is no longer tested from there on.
my $f;
$f = sub {
if (/alpha/) {
do_alpha();
$f = \&do_beta;
} else {
do_beta();
}
};
while (<DATA>) {
$f->();
}
sub do_alpha {
print "do_alpha(): \$f = $f, \$_ = $_";
}
sub do_beta {
print "do_beta(): \$f = $f, \$_ = $_";
}
__DATA__
beta
beta
beta
beta
alpha
beta
beta
beta
beta
beta
beta
beta
beta
Output:
do_beta(): $f = CODE(0x796e88), $_ = beta
do_beta(): $f = CODE(0x796e88), $_ = beta
do_beta(): $f = CODE(0x796e88), $_ = beta
do_beta(): $f = CODE(0x796e88), $_ = beta
do_alpha(): $f = CODE(0x796e88), $_ = alpha
do_beta(): $f = CODE(0x7c6ee8), $_ = beta
do_beta(): $f = CODE(0x7c6ee8), $_ = beta
do_beta(): $f = CODE(0x7c6ee8), $_ = beta
do_beta(): $f = CODE(0x7c6ee8), $_ = beta
do_beta(): $f = CODE(0x7c6ee8), $_ = beta
do_beta(): $f = CODE(0x7c6ee8), $_ = beta
do_beta(): $f = CODE(0x7c6ee8), $_ = beta
do_beta(): $f = CODE(0x7c6ee8), $_ = beta
As you can see, the coderef changes after alpha has been encountered.
(upd: as it seems, BrowserUk posted essentially the same idea while I wrote up my reply...) | [reply] [d/l] [select] |
A reply falls below the community's threshold of quality. You may see it by logging in. |
Re: A way to avoid repeated conditional loops
by Marshall (Canon) on Aug 24, 2011 at 13:45 UTC
|
The below is one way:
Keep things simple.
Output of below is: term 'alpha' detected on input line 4
The code below is very efficient and runs fast.
#!usr/bin/perl -w
use strict;
while (<DATA>)
{
if(/\balpha\b/)
{
print "term 'alpha' detected on input line $.\n";
next;
}
.. do something here...
.. sometimes better than elsif()
}
__DATA__
beta
beta
beta
alpha # this line appears only once in the whole file
beta
beta
beta
if you have a lot of conditions, then perhaps something like this is appropriate:
while ( <FILE> )
{
if ( /alpha/ )
{
....
next;
}
if (/beta/)
{
....
next;
}
#here is the default code...
}
One of the reasons to do it that way is so that all of the conditions can be interchanged with one another. If you have an if(..)elsif(..)else(..) conditional, this hinders the ability to change the order of the conditions. At the end of the day, that approach will result in more complex code and limit the ability to re-order the code's priority of matching - don't do it. At least for number of "if" statements of about 5-6.
Update: Well this is one of those situations where there just isn't a "one size fits all" solution. I tend to prefer coding with several sequential if{..} statements so that all of them are "equal". This whole coding style discussion can set off something that will last until a gallon of gas falls back to $1.60. | [reply] [d/l] [select] |
Re: A way to avoid repeated conditional loops
by BrowserUk (Patriarch) on Aug 24, 2011 at 19:26 UTC
|
You can always disable the warning if it bothers you. Of course, its only a significant gain if the alpha appears early in the file. And, the sub overhead may kill the gain, if the processing involved isn't very significant:
#! perl -slw
use strict;
sub doBeta(_) {
print 'Beta';
}
sub doit(_) {
if( /alpha/ ) {
print 'Alpha';
*doit = \&doBeta;
return;
}
doBeta( $_ );
}
doit( $_ ) while <DATA>;
__DATA__
beta
beta
beta
beta
beta
beta
beta
beta
beta
alpha
beta
beta
beta
beta
beta
beta
beta
beta
beta
beta
beta
beta
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
Re: A way to avoid repeated conditional loops
by Not_a_Number (Prior) on Aug 24, 2011 at 19:08 UTC
|
Hi.
Frankly, if your dataset is as described in your OP, of all the solutions posted above, I prefer your original one!
It has two major advantages over many of the other solutions provided:
1. It works!
2 . It is extremely comprehensible.
| [reply] |
Re: A way to avoid repeated conditional loops
by TomDLux (Vicar) on Aug 24, 2011 at 19:25 UTC
|
use autodie;
open my $file, '<', $filepath;
process_file_header( $file );
proress_file_remainder( $file );
As Occam said: Entia non sunt multiplicanda praeter necessitatem.
| [reply] [d/l] |
Re: A way to avoid repeated conditional loops
by locked_user sundialsvc4 (Abbot) on Aug 24, 2011 at 12:22 UTC
|
Call it “a flag variable” if you want to, but this is a classic place for a finite-state machine (FSM) algorithm. I presume that you are familiar with the term.
Edit: One subtle distinction that sometimes comes in handy with FSM algorithms is to put “read the next line” as a subroutine-call that occurs within each state-handler, instead of structuring the algorithm within a while-loop as shown above. Sometimes you might want to loop through more than one consecutive state while processing the same line.
| |
Re: A way to avoid repeated conditional loops
by Anonymous Monk on Aug 25, 2011 at 10:20 UTC
|
#!/usr/bin/perl
use warnings;
use strict;
while (<DATA>) {
if (m?alpha?) {
print "+ $_";
} else {
print "- $_";
}
}
__DATA__
beta
beta
alpha
beta
beta
alpha
alpha
beta
Results in:
- beta
- beta
+ alpha
- beta
- beta
- alpha
- alpha
- beta
| [reply] [d/l] [select] |
|
|
| [reply] |
|
|
=~ s/^alpha/^#alpha/
... and now do what you want with the whole file
| [reply] [d/l] |