views:

242

answers:

12

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.

+5  A: 

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.

Nik
+2  A: 

Generally, no.

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

Steven Sudit
+1  A: 

Is this what you are looking for ?

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

Using Linq,

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

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

Joel Rondeau
The performance difference between these two is almost surely irrelevant. The original is more readable, and idiomatic. It's certainly possible to write `Enumerable.Range(0, 10).ToList().ForEach(x => Console.WriteLine(x));` instead of `for(int i = 0; i < 10; i++) { Console.WriteLine(i); }` but that's just going to piss people off. "No one ever writes let `6` be a group."
Jason
@Jason - I agree that if I saw what I wrote in production code, I'd be pissed off. Was more of a "one line to explain a way to do it" than "follow this exactly". Really, I agree with the people suggesting the switch statements.
Joel Rondeau
+1  A: 

How about:

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

It's a hack though :)

Or if you don't mind creating your own extension method, you can create the following:

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

And you can use it like this:

if (1.In(1, 2))

:)

Amry
+11  A: 

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);
    }
}
Paolo Tedesco
needs a return type, but an extension method is what I was going to suggest as well
Daniel DiPaolo
@Daniel: yes, fixed, thanks :)
Paolo Tedesco
+1. Nice solution, just like mine, but yours using Generics. I'll replace mine with yours :)
Guilherme Oenning
I really like this version. I figured I might have to build my own method.
Ricky
Couldn't you have written `return values.Contains(t)`? Or `return values.Any(v => t.Equals(v))`?
Kobi
A: 

Using Extension Mehtods:

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"))
{ 
    ...
} 
Guilherme Oenning
A: 
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;
}
JWL_
+2  A: 

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
}
jules
I wouldn't even say "alternatively", this is the closest analogy to the SQL use of IN with a list given in the example (`Contains()` etc. corresponding more with IN against the results of a subquery).
Jon Hanna
+1  A: 

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.

Tim
+1  A: 

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"));
Allrameest
A: 

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.

supercat