[c#] if statements matching multiple values

Any easier way to write this if statement?

if (value==1 || value==2)

For example... in SQL you can say where value in (1,2) instead of where value=1 or value=2.

I'm looking for something that would work with any basic type... string, int, etc.

This question is related to c# if-statement

The answer is


If you have a List, you can use .Contains(yourObject), if you're just looking for it existing (like a where). Otherwise look at Linq .Any() extension method.


If you search a value in a fixed list of values many times in a long list, HashSet<T> should be used. If the list is very short (< ~20 items), List could have better performance, based on this test HashSet vs. List performance

HashSet<int> nums = new HashSet<int> { 1, 2, 3, 4, 5 };
// ....
if (nums.Contains(value))

Using Linq,

if(new int[] {1, 2}.Contains(value))

But I'd have to think that your original if is faster.


I had the same problem but solved it with a switch statement switch(a value you are switching on) { case 1: the code you want to happen; case 2: the code you want to happen; default: return a value }


Using Extension Methods:

public static class ObjectExtension
{
    public static bool In(this object obj, params object[] objects)
    {
        if (objects == null || obj == null)
            return false;
        object found = objects.FirstOrDefault(o => o.GetType().Equals(obj.GetType()) && o.Equals(obj));
        return (found != null);
    }
}

Now you can do this:

string role= "Admin";
if (role.In("Admin", "Director"))
{ 
    ...
} 

public static bool EqualsAny<T>(IEquatable<T> value, params T[] possibleMatches) {
    foreach (T t in possibleMatches) {
        if (value.Equals(t))
            return true;
    }
    return false;
}
public static bool EqualsAny<T>(IEquatable<T> value, IEnumerable<T> possibleMatches) {
    foreach (T t in possibleMatches) {
        if (value.Equals(t))
            return true;
    }
    return false;
}

Easier is subjective, but maybe the switch statement would be easier? You don't have to repeat the variable, so more values can fit on the line, and a line with many comparisons is more legible than the counterpart using the if statement.


Alternatively, and this would give you more flexibility if testing for values other than 1 or 2 in future, is to use a switch statement

switch(value)
{
case 1:
case 2:
   return true;
default:
   return false
}

Generally, no.

Yes, there are cases where the list is in an Array or List, but that's not the general case.


A more complicated way :) that emulates SQL's 'IN':

public static class Ext {    
    public static bool In<T>(this T t,params T[] values){
        foreach (T value in values) {
            if (t.Equals(value)) {
                return true;
            }
        }
        return false;
    }
}

if (value.In(1,2)) {
    // ...
}

But go for the standard way, it's more readable.

EDIT: a better solution, according to @Kobi's suggestion:

public static class Ext {    
    public static bool In<T>(this T t,params T[] values){
        return values.Contains(t);
    }
}

Is this what you are looking for ?

if (new int[] { 1, 2, 3, 4, 5 }.Contains(value))

An extensionmethod like this would do it...

public static bool In<T>(this T item, params T[] items)
{
    return items.Contains(item);
}

Use it like this:

Console.WriteLine(1.In(1,2,3));
Console.WriteLine("a".In("a", "b"));

In vb.net or C# I would expect that the fastest general approach to compare a variable against any reasonable number of separately-named objects (as opposed to e.g. all the things in a collection) will be to simply compare each object against the comparand much as you have done. It is certainly possible to create an instance of a collection and see if it contains the object, and doing so may be more expressive than comparing the object against all items individually, but unless one uses a construct which the compiler can explicitly recognize, such code will almost certainly be much slower than simply doing the individual comparisons. I wouldn't worry about speed if the code will by its nature run at most a few hundred times per second, but I'd be wary of the code being repurposed to something that's run much more often than originally intended.

An alternative approach, if a variable is something like an enumeration type, is to choose power-of-two enumeration values to permit the use of bitmasks. If the enumeration type has 32 or fewer valid values (e.g. starting Harry=1, Ron=2, Hermione=4, Ginny=8, Neville=16) one could store them in an integer and check for multiple bits at once in a single operation ((if ((thisOne & (Harry | Ron | Neville | Beatrix)) != 0) /* Do something */. This will allow for fast code, but is limited to enumerations with a small number of values.

A somewhat more powerful approach, but one which must be used with care, is to use some bits of the value to indicate attributes of something, while other bits identify the item. For example, bit 30 could indicate that a character is male, bit 29 could indicate friend-of-Harry, etc. while the lower bits distinguish between characters. This approach would allow for adding characters who may or may not be friend-of-Harry, without requiring the code that checks for friend-of-Harry to change. One caveat with doing this is that one must distinguish between enumeration constants that are used to SET an enumeration value, and those used to TEST it. For example, to set a variable to indicate Harry, one might want to set it to 0x60000001, but to see if a variable IS Harry, one should bit-test it with 0x00000001.

One more approach, which may be useful if the total number of possible values is moderate (e.g. 16-16,000 or so) is to have an array of flags associated with each value. One could then code something like "if (((characterAttributes[theCharacter] & chracterAttribute.Male) != 0)". This approach will work best when the number of characters is fairly small. If array is too large, cache misses may slow down the code to the point that testing against a small number of characters individually would be faster.