Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Range Operator in If Statement

by mmartin (Monk)
on Jan 04, 2012 at 20:26 UTC ( #946284=perlquestion: print w/ replies, xml ) Need Help??
mmartin has asked for the wisdom of the Perl Monks concerning the following question:

Hey Monks,

My Version:
Perl v5.8.8

I have a pretty simple question if someone could help me with...?

How do I use the range operator in an if statement (or is it possible) on a variable that is a number?

For Example:

my $ref = 7; if ($ref = 1 .. 8) { ...code.... }
In other words say, if $ref is between 1 and 8 then do stuff...
I've tried the above code in like 20 different ways but keep getting errors.

I've tried:
if ($ref =~ 1..8) if ($ref = 1..8) if ($ref == 1 .. 8) if ($ref =~ (1 .. 8)) etc...


Any thoughts would be great!


Thanks in Advance,
Matt


.

Comment on Range Operator in If Statement
Select or Download Code
Re: Range Operator in If Statement
by Perlbotics (Abbot) 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.
      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
        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.
        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

        Cheers Rolf

        If you have multiple consecutive intervals, it's better to use an elsif cascade, such as

        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.
Re: Range Operator in If Statement
by toolic (Chancellor) 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"; }
      toolic, thanks for the reply...

      Sweet deal... I just cpan-ed it and I will give it a try.


      Thanks alot,
      Matt
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 ] ) { ... }
Re: Range Operator in If Statement
by ww (Bishop) 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

Re: Range Operator in If Statement
by LanX (Canon) 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

    Cheers Rolf

Re: Range Operator in If Statement
by NetWallah (Abbot) on Jan 05, 2012 at 04:52 UTC
    In the TIMTOWTDI tradition, I offer Quantum::Superpositions (untested):
    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

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"; } }
Re: Range Operator in If Statement
by GrandFather (Cardinal) 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
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


      I'm SURE there is a 100 different ways to do this...

      Here's one way to assign to $bundle that requires a lot less typing. Replace your call to get_bundle and the sub itself with:

      $bundle = [ 'A' .. 'F' ]->[ ( $ref_number - 1 ) / 8 ];

      Update: Removed unnecessary parentheses around the arrayref.

        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


Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (5)
As of 2014-08-30 21:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (294 votes), past polls