Question

Can I achieve

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

instead of

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

?

Was it helpful?

Solution

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 (that is, 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" };
        }
    }
}

OTHER TIPS

Well, the closest to that you can get is:

switch (a) {
   case "b":
   case "c":
      // variable a is either "b" or "c"
      break;
}

To my knowledge that isn't an option.

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)$"))

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.

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.

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;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top