Omu
Omu

Reputation: 71228

C#. Do if( a == (b or c or d)). Is it possible?

Is there another way to write something like this:

if (a == x || a == y || a == z)

One way that I found is doing it like this:

if( new [] {x,y,z}.Contains(a))

Are there other good ways?

Upvotes: 28

Views: 17576

Answers (11)

TheGeneral
TheGeneral

Reputation: 81513

Fun fact, as of C#9 this is possible

var c ='b';

if (c is 'a' or 'b' or 'c')
  Console.WriteLine("yes");

Which compiles to

if (c == 'a' || c == 'b' || c == 'c')
{
   Console.WriteLine("yes");
}

Or you can get more creative

if (c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z') or '.' or ',')
   Console.WriteLine("yes");

Which would roughly compile to (according to sharp io)

if (c >= 'a')
{
   if (c <= 'z')
   {
      goto IL_0025;
   }
}
else if (c >= 'A')
{
   if (c <= 'Z')
   {
      goto IL_0025;
   }
}
else if (c == ',' || c == '.')
{
   goto IL_0025;
}
bool flag = false;
goto IL_002b;
IL_0025:
flag = true;
goto IL_002b;
IL_002b:
if (flag)
{
   Console.WriteLine("yes");
}

Or use it in a switch

switch (c)
{
   case 'a' or 'b' or 'c':
      Console.WriteLine("yes");
   break;
}

Upvotes: 4

Danko Durbić
Danko Durbić

Reputation: 7247

Consider a case where a == x, and y and z are slow-to-evaluate, expensive functions.

  • In if(a == x || a == y || a == z) you have the benefit of the short-circuit ||-operator, so you y and z won't be evaluated.
  • If you make an array with new[] { x, y, z } - y and z will be evaluated every time.

The 'trick' with .Contains() would be more useful if there was an elegant syntax to create lazy-evaluated sequence (IEnumerable<T>). i.e. something like yield return x; yield return y;..., but inlined and shorter.

Upvotes: 5

Toan Nguyen
Toan Nguyen

Reputation: 11591

For instance, your logic is like that:

if(a==x || a== y|| a==z)
{
    DoSomething();
} 
else
{
   DoOtherThings();
}

will equivalent to:

if(a!=x&& a != y && a!= z)
{
   DoOtherThings();
}
else
{
   DoSomething();
}

Cheers.

Upvotes: 0

GrahamS
GrahamS

Reputation: 10350

Your solution to rewrite it as

if( new [] {x,y,z}.Contains(a))

is not a good move.

You've take a simple efficient logical operation, which every programmer easily understands and which contains short-circuiting logic to speed it up and instead you've produced code that requires a moment to understand and which is considerably less efficient.

Sometimes your fellow engineers will prefer it if you don't try to be "clever"!

Upvotes: 6

RameshVel
RameshVel

Reputation: 65877

Try this

var res2 = new[] { 1, 2, 3 }.Any(x => x == 2);

Upvotes: 1

David Hedlund
David Hedlund

Reputation: 129802

I often use an extension method that mimics SQLs IN:

public static bool IsIn<T>(this T obj, params T[] collection) {
   return collection.Contains(obj);
}

That way I can do

if(a.IsIn(b, c, d)) { ... }

Upvotes: 64

Yakimych
Yakimych

Reputation: 17752

Why would you need yet another way? Since it isn't a matter of functionality, I would guess the point is to improve readability. If you have a few variables with meaningful names, it would be more readable to just compare by using ==. If you have more, you can use Contains against a list as in your other sample. Yet another way would be comparing against enum flags:

[Flags]
public enum Size
{
    Small = 1,
    Medium = 2,
    Large = 4
}

And then to find out if mySize is in Small or Medium:

selectedSizes = Size.Small | Size.Medium;
mySize = Size.Small;
if (mySize & selectedSizes)
{
  ... 
}

Upvotes: 2

Skizz
Skizz

Reputation: 71080

So, you want to replace a simple, efficent language construct that contains short-circuit optimisations into something much slower that has the potential for throwing exceptions?

However, if the items you want to compare against are not fixed in quantity, i.e. at run time it could be t,u,v,w,x,y,z,etc..., then the Collection.Contains method is the only option, but then you'd be passing collection objects around rather than individual values and so there's little memory allocation ovrehead.

If you've got a large number of items to compare 'a' against, but the items are not dynamic at run time then a switch statement might be a better fit.

Upvotes: 3

didxga
didxga

Reputation: 6125

if(a==x?true:a==y?true:a==z?true:false)

Upvotes: 0

Paolo Tedesco
Paolo Tedesco

Reputation: 57202

Just for fun:

using System;

static class Program {

    static bool In(this object obj, params object[] values) {
        foreach (object value in values) {
            if (obj.Equals(value)) {
                return true;
            }
        }
        return false;
    }

    static void Main(string[] args) {
        bool test1 = 3.In(1, 2, 3);
        bool test2 = 5.In(1, 2, 3);
    }
}

But I really think that the best way is to write the plain check

if(a == x || a == y || a == z)

As everybody will understand immediately what it does.

Upvotes: 6

Mongus Pong
Mongus Pong

Reputation: 11477

You have the classic switch statement :

switch(a) {
    case x:
    case y:
    case z:
        // Do stuff
        break;
}

Upvotes: 12

Related Questions