Switch Statement Question

Welcome Forums General PowerShell Q&A Switch Statement Question

This topic contains 8 replies, has 4 voices, and was last updated by

 
Participant
1 year, 3 months ago.

  • Author
    Posts
  • #78391

    Participant
    Points: 0
    Rank: Member

    Can anyone tell me why this statement is working the way it is?

    PS C:\> switch (1) {  
      {1 -or 3 -or 5 -or 7 -or 9} { "Odd"}
      {2 -or 4 -or 6 -or 8 -or 10} { "Even"}
    }
    Odd
    Even 
    

    however, this works as expected:

    PS C:\> switch (1) {  
      {$_ -eq 1 -or $_ -eq 3 -or $_ -eq 5 -or $_ -eq 7 -or $_ -eq 9} { "Odd"}
      {$_ -eq 2 -or $_ -eq 4 -or $_ -eq 6 -or $_ -eq 8 -or $_ -eq 10} { "Even"}
    }
    Odd
    
  • #78392

    Keymaster
    Points: 1,704
    Helping HandTeam Member
    Rank: Community Hero

    Boolean operators don't work like that.

    "1 -or 3"

    Is being taken as a comparison of 1 OR 3, which is done as a bitwise comparison. In your second example

    "$_ -eq 1"

    You're correctly comparing the input ($_) to a value (1).

    I realize that your first example "reads" better in English, but that isn't how PowerShell (or any other language, really) sees it ;).

    • #78394

      Participant
      Points: 0
      Rank: Member

      But then why does this work?

      PS C:\> switch ("A") {  
        {"A" -or "B"} { "-HERE-"}
        "B" { "-NOT HERE-"}
      }
      -HERE-
      
      PS C:\> switch ("B") {  
        {"A" -or "B"} { "-HERE-"}
        "B" { "-NOT HERE-"}
      }
      -HERE-
      -NOT HERE-
      
      
  • #78395

    Participant
    Points: 1
    Rank: Member

    Like Don Jones said, you have to compare everything with the value you want to test.
    But there are numreous outions to that problem.
    Look at these :

    if (2 -match "2|4|6|8|10|12" ) {"even"}
    1..20 | % {if($_ % 2 -eq 0 ) {"$_ is even"} }

    I like the last one, it (almost) never fails!

    • #78397

      Participant
      Points: 1
      Rank: Member

      Look at this on:

      switch ("C") {  
        {"A" -or "B"} { "-HERE-"}
        { "B"} { "-NOT HERE-"}
      }
      -HERE-
      -NOT HERE-

      So its not doing what you think it does.

    • #78404

      Participant
      Points: 0
      Rank: Member

      So, yea, I just saw that.

      I guess my issue is that I'm trying to equate the PowerShell switch with a C# or C switch statement and when you use an Expression via {} it behaves differently.

      The best conclusion in my mind is to *not* use {}

    • #78400

      Participant
      Points: 0
      Rank: Member

      I'm not questioning the odd/even function, but why is the switch statement operating this way.
      My understanding is that the PowerShell switch works on evaluating each item as a condition
      PowerShell Switch

      Switch ()
      {
           {}
           {}
      }
      

      and that a condition can be a '"string"|number|variable|{ expression } '

      switch [-regex|-wildcard|-exact][-casesensitive] ()
      {
          "string"|number|variable|{ expression } { statementlist }
          default { statementlist }
      }
      

      This would indicate to me that if () matches the { expression } then { statementlist } is executed.

      So some simple tests:

      PS C:\> 1 -eq (&{1 -or 3 -or 5 -or 7 -or 9})
      True
      
      PS C:\> 2 -eq (&{1 -or 3 -or 5 -or 7 -or 9})
      False
      

      I *think* the parser is turning this into 1 -eq $true and 2 -eq $true

      Why does this work???

      PS C:\> switch ("A") {  
        {"A" -or "B"} { "-HERE-"}
        "B" { "-NOT HERE-"}
      }
      -HERE-
      
      PS C:\> switch ("B") {  
        {"A" -or "B"} { "-HERE-"}
        "B" { "-NOT HERE-"}
      }
      -HERE-
      -NOT HERE-
      
    • #78422

      Participant
      Points: 0
      Rank: Member

      As far as the "simple tests", you must test both ways to ensure the test is valid

      1 -eq (&{1 -or 3 -or 5 -or 7 -or 9})
      True
      
      2 -eq (&{1 -or 3 -or 5 -or 7 -or 9})
      False
      
      1 -eq (&{2 -or 3 -or 5 -or 7 -or 9})
      True
      
      2 -eq (&{2 -or 3 -or 5 -or 7 -or 9})
      False
      

      As you see, this test fails

      And while I know you have the working solution of using the full $_ -eq Value for each -or, I wanted to go ahead and throw some alternatives.

      $num = 1
      
      switch -Regex ($num) {  
        "^(1|3|5|7|9)$" { "Odd"}
        "^(2|4|6|8|10)$" { "Even"}
      }
      
      switch ($num) {  
        {$_ -in (1,3,5,7,9)} { "Odd"}
        {$_ -in (2,4,6,8,10)} { "Even"}
      }
      
      #The ones above work on a predefined list, but this one will work no mater what number you throw at it unless it's a negative number.
      switch ($num % 2) {  
        0 { "Even"}
        1 { "Odd"}
      }
  • #78410

    Keymaster
    Points: 1,704
    Helping HandTeam Member
    Rank: Community Hero

    Honestly, you're not meant to use -or and -and that way. Those operators expect both operands to be either True or False. When confronted with a string or number or other non-Boolean values, there are coercion rules. For example:

    0 -or 1

    Will be True, because 0 is False and 1 is True.

    "A" -or "B"

    Will be True, because both "A" and "B" are regarded as True values (basically, any nonzero value is True).

    In your final example, bear in mind that unless you break out of the construct, each condition matching True will execute.

    "A" -or "B" does not read as "If the value is A or the value is B." Because you've enclosed the expression in {}, it executes as a script block, within which $_ represents the comparable value. If the {block} returns True, the matching expression executes.

    { $_ -eq "A" -or $_ -eq "B" } would read as "If the value is A or the value is B," because -or is being provided two subexpression, either of which will evaluate to True or False.

The topic ‘Switch Statement Question’ is closed to new replies.