Re: Range Operator in If Statement
by Perlbotics (Archbishop) on Jan 04, 2012 at 20:45 UTC
|
If you insist in using a range-/list-op, you could do:
if ( grep { $ref == $_ } 1..8 ) { ... }
But personally, I would rather use something like
if ( $ref >= 1 and $ref <= 8 ) { ... }
or maybe
if ( $ref =~ /^[1-8]$/ ) { ... }
Update: (in response to OP's reply below)
With a modern Perl, you could use given/when:
use v5.10;
use strict;
use warnings;
my @tests = qw(1 9 17 25 33);
my $range_25_32 = [25..32]; # alternatve, maybe(?) faster
for my $ref ( @tests ) {
given ( $ref ) {
when ( [1..8] ) { say "A $ref" }
when ( [9..16] ) { say "B $ref" }
when ( [17..24] ) { say "C $ref" }
when ( $range_25_32 ) { say "D $ref" }
default { say "ELSE $ref" }
}
}
Output:
A 1
B 9
C 17
D 25
ELSE 33
With the given ranges in the example below, some bitwise operators might also work.
| [reply] [d/l] [select] |
|
|
Hey perlbotics, thanks for you QUICK reply...
Ohh ok I thought I could use the range operator for this type of thing, but guess not.
I wanted to use that because it seemed like it was the "shorthand" way of doing it.
Wanted a short way because I needed a whole bunch of those statements and I didn't want to have a ton of these statements:
if ($ref >= 1 && $ref <= 8) { ...... }
if ($ref >= 9 && $ref <= 16) { ...... }
if ($ref >= 17 && $ref <= 24) { ...... }
if ($ref >= 25 && $ref <= 32) { ...... }
#....more checks
But if that's what you recommend then I'll just use my original way I had like above and like you had...
Thanks again for the reply,
Matt
| [reply] [d/l] |
|
|
This looks like a power of 2 problem. If you could give us some more detail about what you are doing, I think some very efficient solutions might be forthcoming.
| [reply] |
|
|
When classifying by intervals, better try $case = int( ($ref-1) / 8 ) , so you only have to test for the results 0,1,2,3...
DB<104> for $ref (1,8,9,16,17,24,25,32) { print "$ref: ", int(($ref-1)
+/8), "\n" }
1: 0
8: 0
9: 1
16: 1
17: 2
24: 2
25: 3
32: 3
| [reply] [d/l] [select] |
|
|
if ($ref <= 8) {
say "ref is at most 8.";
} elsif ($ref <= 16) {
say "ref is above 8 but at most 16."
} elsif ($ref <= 24) {
say "ref is above 16 but at most 24."
} elsif ($ref <= 32) {
say "ref is above 24 but at most 32."
} else {
sat "ref is above 32."
}
The elsif part means that if the previous condition was found true, the next one is not tested for, so eg. if $ref = 5 then the first branch is executed, the rest of the tests and branches are skipped.
| [reply] [d/l] [select] |
Re: Range Operator in If Statement
by toolic (Bishop) on Jan 04, 2012 at 20:53 UTC
|
...or, you could reuse an existing function from Acme::Tools
(or create your own function)
use warnings;
use strict;
use Acme::Tools qw(between);
my $ref = 7;
if (between($ref, 1, 8)) {
print "between\n";
}
| [reply] [d/l] |
|
|
toolic, thanks for the reply...
Sweet deal... I just cpan-ed it and I will give it a try.
Thanks alot,
Matt
| [reply] |
Re: Range Operator in If Statement
by kejohm (Hermit) on Jan 04, 2012 at 21:35 UTC
|
If you are able to upgrade to a newer version of Perl, starting with v5.10, you can use the smart match operator, eg:
use 5.010;
my $ref = 7;
if ( $ref ~~ [ 1 .. 8 ] ) {
...
}
| [reply] [d/l] |
Re: Range Operator in If Statement
by ww (Archbishop) on Jan 04, 2012 at 22:12 UTC
|
Another way, perhaps even related to the code in OP:
#!/usr/bin/perl
use Modern::Perl;
# 946284
my $ref = 7;
for (1 .. 8 ) {
if ($ref == $_) {
say "\$ref: $ref"; # adjust output to id source of match?
} else {
say "Tain't workin'";
}
}
Seems to me this might be readily expansible to your larger goal as outlined in Re^2: Range Operator in If Statement | [reply] [d/l] |
Re: Range Operator in If Statement
by LanX (Saint) on Jan 05, 2012 at 01:40 UTC
|
Just to clarify why your tests don't throw errors:
When you're using the .. range operator in scalar context, you are actually getting the flip-flop behavior!
see Range Operators
I recommend combining two <= operators with &&, testing for inclusion after generating temporary lists is too much overhead. There is nothing closer to Python's 1 <= x <= 8 in Perl.
HTH
| [reply] [d/l] [select] |
Re: Range Operator in If Statement
by NetWallah (Canon) on Jan 05, 2012 at 04:52 UTC
|
use Quantum::Superpositions;
if ( $ref == any(1..8) ) {
"Battle not with trolls, lest ye become a troll; and if you gaze into the Internet, the Internet gazes also into you."
-Friedrich Nietzsche: A Dynamic Translation
| [reply] [d/l] |
Re: Range Operator in If Statement
by GrandFather (Saint) on Jan 05, 2012 at 06:26 UTC
|
You've got a bunch of answers to the question you asked, but (as suggested in one answer) it looks like we could give you a better answer if we knew what you are trying to do. There may be a nifty trick we could tell you about if you really are doing something related to powers of 2 or something of that sort so how about giving us a little more back story to work with?
True laziness is hard work
| [reply] |
Re: Range Operator in If Statement
by mmartin (Monk) on Jan 05, 2012 at 15:14 UTC
|
Wow, thanks everybody, what a response..!!
kejohm,
In terms of updating to Perl 5.10 and using the Smart Match Operator. I did look into that but updating the Perl version wasn't really an option at the moment bc it is a production server and a bunch of things running depend on that. But I did want to try to use that at some point...
ww,
Thanks for the reply, The example you show is sort of what I was trying to achieve with the ranges, maybe I'll give that one a try as well. Thanks again!
LanX,
Oh ok I gotcha... Bc it was working just not in the way I thought it would...? Thanks for the info.
NetWallah,
Hey, that looks cool I'll have to look into that Module as well. Seems alot like the Acme::Tools Module that I eventually went with from toolic's suggestion... Thanks I'll have to download that Module.
TJPride,
That's a good one..! I like that! Don't know why I didn't think of that. Clean and simple, since the control structure, once it finds a match, it will drop out of the if/elsif clause which leads to not having to use a range to test on, but just one test instead... Cool thanks..!
GrandFather,
Hey thanks for the reply. Sorry it took me a while to respond back but I decided to go with toolic's suggestion with the ACME::Tools solution... Works Good!
But in terms of a backstory. The thing I need this for is a script to run along side with MRTG and Interafce Templates to check which GigabitEthernet port it is and then separate them into groups to test for Backplane usage on a Cisco switch. Backplane is Bundeled ports (usually 8 consecutive one's) ranging from (Gi3/1<-->Gi3/48; Gi4/1<-->Gi4/48; ... all the way to ... Gi7/1<-->Gi7/48).
So basically some of the groups would be in ranges as follows... For example the range Gi3/1..Gi3/8 would be "Bundle-Gi3A", and Gi3/9..Gi3/16 would be "Bundle-Gi3B" all the way up to Bundle-Gi3F. As for Gi4 -to- Gi7 it would be the same Letters only difference would be the Gi number...
Here is my entire solution to the original question:
The original question had to do with the Subroutine "get_bundle()"
I know it's a SIMPLE program but here it is. Basically you just pass it the interface name (i.e. "Gi3/7") broken into two pieces, (1) the Gi number "Gi3" and (2) the reference number "7", which is passed from an MRTG Template/Script and then passed back to the Template to be added to the config ("cfg") file.
#!/usr/bin/perl
use warnings;
use strict;
use Getopt::Long;
use Acme::Tools qw(between);
# Declare Command Line Option's Variables
my $Gi_number;
my $ref_number;
my $get_what;
# Declare regular variables
my $bundle;
my $target_lines;
#my $target_name = "target_name";
my @number;
my $GInum;
my $userGraph;
# Process Command-Line Options with the GetOptions::Long Module
if ( @ARGV > 0 ) {
GetOptions('Gi_number=s' => \$Gi_number,
'ref_number=s' => \$ref_number);
}
### Extract the 'Gi' Number (i.e. Gi4 --> '4') and set it to $GInum
@number = ($Gi_number =~ /(\d)/);
$GInum = $number[0];
&get_bundle();
### Build the the UserDefined Graph Name for the routers.cgi*Graph[] L
+ine
$userGraph = "Bundle-$Gi_number$bundle";
if ($bundle) {
$target_lines .= "routers.cgi*Graph[\$target_name]: $userGraph tot
+al average active\n";
} else {
print "WARNING: No Bundle Letter has been assigned to \$bundle
+... Try again.\n";
exit 2;
}
######################################################################
+##############
# SUB - get_bundle() --- This sub will take the interface reference nu
+mber Gi3/"7" #
# which is the '7' and get the corresponding Bundle letter
+s.#
######################################################################
+##############
sub get_bundle()
{
if (between($ref_number, 1, 8)) { $bundle = "A"; }
if (between($ref_number, 9, 16)) { $bundle = "B"; }
if (between($ref_number, 17, 24)) { $bundle = "C"; }
if (between($ref_number, 25, 32)) { $bundle = "D"; }
if (between($ref_number, 33, 40)) { $bundle = "E"; }
if (between($ref_number, 41, 48)) { $bundle = "F"; }
}
######################################################################
+###########
### END: get_bundle()
print "$target_lines";
I'm SURE there is a 100 different ways to do this, but this works for my current situation...
I REALLLY want to thank all of you for your suggestions, it was MUCH MUCH more then I expected..!!
Thanks Again Everybody,
Matt
| [reply] [d/l] |
|
|
| [reply] [d/l] [select] |
|
|
Not_a_Number, thanks for the reply...
Cool stuff... Could you explain a little how that works exactly? I'm still relatively new to Perl.
Thanks,
Matt
| [reply] |
|
|
|
|
|
|
DB<118> for $ref (1,8,9,16,17,24,25,32) { print "$ref: ", chr(65+($r
+ef-1)/8), "\n" }
1: A
8: A
9: B
16: B
17: C
24: C
25: D
32: D
| [reply] [d/l] |
Re: Range Operator in If Statement
by TJPride (Pilgrim) on Jan 05, 2012 at 05:29 UTC
|
If the ranges you're matching on are consecutive, you could do something like this:
use strict;
use warnings;
for (-4, 1, 7, 12, 89, 54, 13, 104) {
if ($_ < 1 || $_ > 64) { print "$_ outside.\n" }
elsif ($_ <= 8) { print "$_ 1-8\n"; }
elsif ($_ <= 16) { print "$_ 9-16\n"; }
elsif ($_ <= 32) { print "$_ 17-32\n"; }
elsif ($_ <= 64) { print "$_ 33-64\n"; }
}
| [reply] [d/l] |