views:

2829

answers:

8
+2  Q: 

OR Operator in c#

Can I achieve

if(a == "b" || "c")

instead of

if(a == "b" || a== "c")
+11  A: 

No.

You can do:

if (new[] { "b", "c" }.Contains(a))

if you have the Linq extensions available, but that's hardly an improvement.


In response to the comment about performance, here's some basic timing code. Note that the code must be viewed with a critical eye, I might have done things here that skew the timings.

The results first:

||, not found: 26 ms
||, found: 8 ms
array.Contains, not found: 1407 ms
array.Contains, found: 1388 ms
array.Contains, inline array, not found: 1456 ms
array.Contains, inline array, found: 1427 ms
switch-statement, not interned, not found: 26 ms
switch-statement, not interned, found: 14 ms
switch-statement, interned, not found: 25 ms
switch-statement, interned, found: 8 ms

All the code was executed twice, and only pass nr. 2 was reported, to remove JITting overhead from the equation. Both passes executed each type of check one million times, and executed it both where the element to find was one of the elements to find it in (ie. the if-statement would execute its block), and once where the element was not (the block would not execute). The timings of each is reported. I tested both a pre-built array and one that is built every time, this part I'm unsure how much the compiler deduces and optimizes away, there might be a flaw here.

In any case, it appears that using a switch-statement, with or without interning the string first, gives roughly the same results as the simple or-statement, which is to be expected, whereas the array-lookup is much more costly, which to me was also expected.

Please tinker with the code, and correct (or comment) it if there's problems.

And here's the source code, rather long:

using System;
using System.Linq;
using System.Diagnostics;
namespace StackOverflow826081
{
    class Program
    {
        private const Int32 ITERATIONS = 1000000;
        static void Main()
        {
            String a;
            String[] ops = CreateArray();
            Int32 count;
            Stopwatch sw = new Stopwatch();
            Int32 pass = 0;
            Action<String, Int32> report = delegate(String title, Int32 i)
            {
                if (pass == 2)
                    Console.Out.WriteLine(title + ": " + sw.ElapsedMilliseconds + " ms");
            };

            for (pass = 1; pass <= 2; pass++)
            {
                #region || operator

                a = "a";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (a == "b" || a == "c")
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("||, not found", count);
                sw.Reset();

                a = "b";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (a == "b" || a == "c")
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("||, found", count);
                sw.Reset();

                #endregion

                #region array.Contains

                a = "a";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (ops.Contains(a))
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("array.Contains, not found", count);
                sw.Reset();

                a = "b";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (ops.Contains(a))
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("array.Contains, found", count);
                sw.Reset();

                #endregion           

                #region array.Contains

                a = "a";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (CreateArray().Contains(a))
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("array.Contains, inline array, not found", count);
                sw.Reset();

                a = "b";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (CreateArray().Contains(a))
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("array.Contains, inline array, found", count);
                sw.Reset();

                #endregion

                #region switch-statement

                a = GetString().Substring(0, 1); // avoid interned string
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    switch (a)
                    {
                        case "b":
                        case "c":
                            count++;
                            break;
                    }
                }
                sw.Stop();
                report("switch-statement, not interned, not found", count);
                sw.Reset();

                a = GetString().Substring(1, 1); // avoid interned string
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    switch (a)
                    {
                        case "b":
                        case "c":
                            count++;
                            break;
                    }
                }
                sw.Stop();
                report("switch-statement, not interned, found", count);
                sw.Reset();

                #endregion                      

                #region switch-statement

                a = "a";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    switch (a)
                    {
                        case "b":
                        case "c":
                            count++;
                            break;
                    }
                }
                sw.Stop();
                report("switch-statement, interned, not found", count);
                sw.Reset();

                a = "b";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    switch (a)
                    {
                        case "b":
                        case "c":
                            count++;
                            break;
                    }
                }
                sw.Stop();
                report("switch-statement, interned, found", count);
                sw.Reset();

                #endregion
            }
        }

        private static String GetString()
        {
            return "ab";
        }

        private static String[] CreateArray()
        {
            return new String[] { "b", "c" };
        }
    }
}
Lasse V. Karlsen
If the array is allocated statically, then performance test might be interesting (if time taken by the expression is long enough to be measured against the overhead of the timing).
Richard
+3  A: 

To my knowledge that isn't an option.

Ian Jacobs
+13  A: 

Well, the closest to that you can get is:

switch (a) {
   case "b":
   case "c":
      // variable a is either "b" or "c"
      break;
}
Guffa
The accepted answer is less code, but using a switch statement has less overhead I believe.
Nathan Ridley
I recommend this solution instead. First, it is more readable. Second, it has less overhead. Third, if the logic has to change in the future it is easier to maintain.
Lucas B
Accepted answer might fit nicer on a single line, but this one doesn't allocate extra memory for an array.
Kon
I would argue that the alternative given in the question - "if(a == "b" || a== "c")" - is the closest you can get and is - in my opinion - a way better solution than introducing the switch-statement.
Patrik Hägne
+2  A: 

No, not with that syntax. But there are many options to code that.

if ("bc".Contains(a)) { } // Maybe check a.Length == 1, too.

if ((a[0] & 0x62) == 0x62) { } // Maybe check a.Length == 1, too.

if (new String[] { "b", "c" }.Contains(a)) { }

Maybe you could do some operator overloading and get your syntax working, but this really depends on what you want to achieve and is hard to tell from your simple example.

Daniel Brückner
A: 

No, this isn't how the or operator (||) works in C#.

An alternate solution, though it makes the code less readable, is to create a function that checks for the value you want, something similar to:

public static bool Any(object a, params object[] b)
{
    foreach(object item in b)
    {
        if(a == b)
        {
            return true;
        }
    }
    return false;
}
Jake Basile
+2  A: 

You can use Regular Expressions:

if(Regex.IsMatch(a, "b|c"))

If the contents of "a" can be longer than one character use this:

if(Regex.IsMatch(a, "^(b|c)$"))
TruthStands
+1  A: 

You can in certain situations. Namely, flagged enumerations:

[Flags]
enum MyEnum {
    None = 0,
    A = 1,
    B = 2,
    C = 4,
    D = 8
}

//...

MyEnum a = MyEnum.B

if((a & (MyEnum.B | MyEnum.C)) > 0)
    // do something

is equivalent to :

if((a & MyEnum.B) > 0 || (a & MyEnum.C) > 0)
    // do something

The reason for this has to do with bit masks. In binary,

None = 00000
A    = 00001
B    = 00010
C    = 00100
D    = 01000

So when we use the | operator, we do a bit-by-bit comparison looking for any 1's in the column and copy them into the result. If there are no 1's in the column, you copy a 0.

  B 00010
& C 00100
---------
    00110

Then when we apply the & operator, we look for 1's in all rows in each column before copying a 1.

  (B & C) 00110
& (a = B) 00010
---------------
          00010

Which is > 0, thus returning true.

Oddly enough, this is the most efficient way to do it, since it saves you a numerical comparison (>) and a logical operator (||), which does all that fancy short circuiting and whatnot.

Daniel Moore
A: 

Sorry, no, this isn't COBOL.

John Saunders