3

just to throw some code out there

string answer = "hotel"
if (answer == "house"|| answer == "hotel" || answer =="appartment")
{
    DoSomething()
}

I was wondering if there was some way to shorten it to

string answer = "hotel"
if (answer == "house"|| "hotel" || "appartment")
{
    DoSomething()
}

I am aware of the switch statement

switch (answer)
{
    case "house":
    case "hotel":
    case "appartment": DoSomething();
        break;
    default :DoNothing();
}

I am just wondering if there is some syntax sugar like what I described above.

General Grey
  • 3,598
  • 2
  • 25
  • 32

10 Answers10

8

It is possible to use some syntactic sugar for this:

if((new[]{"house", "hotel", "apartment"}).Contains(answer))
{
}

Note that this will create a new array on the fly, so will potentially be more expensive than just the Boolean checks.

goric
  • 11,491
  • 7
  • 53
  • 69
  • 2
    Wow that was a lot of the same answer in a very short period of time. You guys are like vultures waiting to swoop in on an answer. Seems goric got the answer first so I will give him credit once my 10 minute waiting period is up. I do see how this could be more expensive because of the array creation, and likely I wont use it(often), but I do like it. – General Grey May 08 '12 at 13:08
  • 1
    @K'Leg: Look my answer to save memory and one which can be used more often. – Nikhil Agrawal May 08 '12 at 13:09
  • @K'Leg Look at my answer for a generic and extendable solution (No, look at mine! let me eat you up with no sugar!) – SimpleVar May 08 '12 at 13:16
  • 1
    @YoryeNathan ok I am scared now – General Grey May 08 '12 at 13:20
  • I am going to go with my original thought. All the answers are more or less the same. There may be slight advantages with re-usability, but this is really what I was going for, straight up SUGAR. Thanks for all your help. – General Grey May 08 '12 at 13:23
7

You could use an array and use Contains.

So in your example:

string answer = "hotel";
string[] acceptable = new string[]{"house", "hotel", "appartment"};
if (acceptable.Contains(answer)){
    DoSomething();
}
jussinen
  • 688
  • 5
  • 16
4
public static bool Any<T>(T item, params T[] items)
{
    return items.Contains(item);
}

Usage:

if (Any(6, 1, 2, 3, 4, 5, 6, 7))
{
    // 6 == 6
}

if (Any("Hi", "a", "cad", "asdf", "hi"))
{
}
else
{
    // "Hi" != "hi" and from anything else.
}

Or:

public string[] items = new string[] {"a", "cad", "asdf", "hi"};

...

if (Any("Hi", items))
{
    Works just as well.
}

You can also have more advanced comparison. For example, if you wanted:

if (person.Name == p1.Name ||
    person.Name == p2.Name ||
    person.Name == p3.Name ||
    person.Name == p4.Name ||
    person.Name == p5.Name || ...)
{
}

You can have:

public static bool Any<T>(T item, Func<T, T, bool> equalityChecker, params T[] items)
{
    return items.Any(x => equalityChecker(item, x));
}

And do:

if (Any(person, (per1, per2) => p1.Name == p2.Name, p1, p2, p3, p4, p5, ...)
{
}

EDIT

If you insist, you can make it, of course, an extension method:

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

Usage:

var b = 6.Any(4, 5, 6, 7); // true

And the same logic of adding the keyword "item" in the signature goes for the overload with the equalityChecker.

SimpleVar
  • 14,044
  • 4
  • 38
  • 60
  • 1
    @Yorke: Include `this` in Extension Method and where are you passing item. It should be `public static bool Any(this params T[] items, T item)` and called like `new int[]{6, 1, 2, 3, 4, 5, 6, 7}.Any(3)` – Nikhil Agrawal May 08 '12 at 13:10
  • @NikhilAgrawal I thought about it, but I didn't really want every object to have that method. Doesn't seem right. – SimpleVar May 08 '12 at 13:11
  • it is an interested approach, but is it not ultimately the same thing as the above answers. I admit I am still a rookie. But are you not still creating an array, and just checking if it contains the first item? Agreed it would bundle well into a custom tools class of some sort – General Grey May 08 '12 at 13:15
  • It is practically the same, except it is generic and allows custom comparing. Eventually, they all check if any of the items equal the item you wish to compare. If you only have one thing you want to check, and it's always the same list of items - I would indeed go for a class-scope list or array to avoid unneeded initializations, but note that you can also call those methods with existing array and they will not recreate one. Edited an example for that in the middle. – SimpleVar May 08 '12 at 13:17
3

Create a Global List and just check it in any method.

List<string> validAnswers = new List<string> {"house", "house1", "apartment"};

if (validAnswers.Contains(answer))
    DoSomething();

In this case your List will not be generated every time answer is checked

Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208
  • 1
    I would rename `str` to `validAnswers` – Svish May 08 '12 at 13:06
  • @NikhilAgrawal how does this save memory? is a list not the same sort of thing as an array? – General Grey May 08 '12 at 13:19
  • @NikhilAgrawal Why saving in a list if you're not going to `.Add` or `.Remove`, etc? Array's are better in cases like this. – SimpleVar May 08 '12 at 13:21
  • yeah that is right but i unlike @Goric said that you should declare this List as Global. In that case if you want to insert any value as accepted answer then you can do so. More over it will be created only once but you can access it and modify it from anywhere in the code. – Nikhil Agrawal May 08 '12 at 13:21
  • List is basically a dynamic array in which we can modify contents at a specific postition without recreating List. Can we do that with arrays where size is fixed. Even if you delete a value in a particualar index it will remain null. – Nikhil Agrawal May 08 '12 at 13:26
  • I see what you are getting at. And perhaps this answer is superior, but by using a global list, you are forcing forthought, which I didn't want to have to do, hence the SUGAR statement. Ultimately it would seem there is no Syntax Sugar, because in this case(and all others so far) you are sacrificing efficiency for ease of typing and readabilty. – General Grey May 08 '12 at 13:34
  • I'd probably use an array as well in this case, and probably have it as a readonly field of the class that needed it or whatever. `var validAnswers = new [] {"A", "B", ... }`. – Svish May 08 '12 at 14:00
  • @K'Leg I'd seriously ignore the performance question in this case, unless it actually is a problem (and you've measured that it makes things much slower). Unless it *really* is a problem, always prefer readability and clarity. Ease of typing is a bonus, but readability should be goal number one in my opinion. – Svish May 08 '12 at 14:02
2

Only thing I can think of is to work with a list or array:

List<String> words = new List<String> { "house", "hotel", "appartment" };
String answer = "house";

if (words.Contains(answer))
{
   DoSomething();
}
bjornruysen
  • 850
  • 1
  • 6
  • 15
1

You can do like

if(new string[]{"house","hotel","appartment"}.Contains(asnwer))
{
...
}

or

if(new List<string>(){"house","hotel","appartment"}.Any(x=>x == answer)
{
}

Can add this like an extension method too, and use...

Tigran
  • 61,654
  • 8
  • 86
  • 123
1

Consider adding an extension method that will accept any strings...

string answer = "hotel"
if (answer.EqualsAny("house", "hotel", "appartment"))
{
    DoSomething()
}
// Extending the thought to another version
if (answer.EqualsAll("house", "hotel", "appartment"))
{
    DoSomething()
}

public static class Extensions
{
    public static bool EqualsAny(this string value, params string[] compareAgainst)
    {
        foreach (var element in compareAgainst)
        {
            if(value == element)
               return true;
        }
        return false;
    }
    public static bool EqualsAll(this string value, params string[] compareAgainst)
    {
        foreach (var element in compareAgainst)
        {
            if(value != element)
                return false;
        }
        return true;
    }
}
Oblivion2000
  • 616
  • 4
  • 9
0

If your comparison parameters are fixed, you can opt for ENUM with Flags. Ref MSDN. Then you can have the desired behavior. You can also refer to this post

Community
  • 1
  • 1
avani gadhai
  • 460
  • 2
  • 12
0

I normally use a switch statement in this case, but as already said in a few answers above you can put the results in an list or array and check it that way.

Gladen
  • 792
  • 2
  • 8
  • 17
  • The nice thing about doing it with switch, is that the compiler can sometimes optimize it and make it faster than the other ways :) – SimpleVar May 08 '12 at 13:25
0

I would use an extension method like this:

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

Use it like this:

if ("hotel".In("house", "hotel", "apartment"))
or
if (1.In(1,2))
Allrameest
  • 4,364
  • 2
  • 34
  • 50