3

I have the following integer that I would like to check the value with an if statement.

int myInt = 3;

I tried this code which works, but I don't like having to write the variable name over and over.

if (myInt == 0 || myInt == 2 || myInt == 3 || myInt == 4)
{
    Debug.WriteLine("Match");              
}
else
{
    Debug.WriteLine("No Match");
}

To demonstrate what I would like to ideally have, I tried something like this:

if (myInt == (0 | 2 | 3 | 4))
{
    Debug.WriteLine("Match");
}
else
{
    Debug.WriteLine("No Match");
}

But this doesn't work because the | is not quite the right operator because there is a type mismatch.

I then tried this, which also worked fine, but I still don't like having to declare an extra array.

if ((new int[] { 0, 2, 3, 4 }).Contains(myInt))
{
    Debug.WriteLine("Match");
}
else
{
    Debug.WriteLine("No Match");
}

The question is:

Is there an operator that can satisfy what I'm trying to accomplish without declaring an additional array or asking for the same variable name over and over with the || operator?

slugster
  • 49,403
  • 14
  • 95
  • 145
IanK.CO
  • 563
  • 5
  • 13

5 Answers5

6

Your question is

Is there an operator that can satisfy what I'm trying to accomplish without declaring an additional array

but it really should be

Is there an operator that can satisfy what I'm trying to accomplish without declaring an additional array every time

There is nothing wrong with having that array once (and initializing it once), but there is a lot wrong with allocating it (and by extension GCing it later) every single time. So You need to declare an array once, something like

private static int matchArray[] = new int[] { 0, 2, 3, 4 };

and later just

if (matchArray.Contains(myInt)) ...

EDIT

If your match array is small, by any means use the answer by @JohnField and not this one - I stand corrected!

Eugen Rieck
  • 64,175
  • 10
  • 70
  • 92
  • Yes good point I didn't consider leaving them lay for GC. This seems to be the most appropriate and elegant method. – IanK.CO Feb 19 '15 at 00:41
3

There is possibly a way to achieve what you want to do. They are called enum flags. Here there is a nice answer that explains how they work.

They way you want to use integers remind me of an enum where you have possibly multiple choices. Let's take the following case for instance:

[Flags]
enum DaysOfTheWeek
{
    Sunday = 1,
    Monday = 2,
    Tuesday = 4,
    Wednesday = 8,
    Thursday = 16,
    Friday = 32,
    Saturday = 64
}

you can declare a variable as follow:

DaysOfTheWeek daysOfTheWeek;
daysOfTheWeek = DaysOfTheWeek.Monday | DaysOfTheWeek.Wednesday | DaysOfTheWeek.Friday;

and then check if your enum contains one of the values assigned above:

if((daysOfTheWeek & DaysOfTheWeek.Monday) == DaysOfTheWeek.Monday)
{
    // Contains Monday!
}
else
{
    // DOES NOT Contain Monday!
}

or from .NET 4 onwards:

if(daysOfTheWeek.HasFlag(DaysOfTheWeek.Monday))
{
...
}

Clearly this method is more elegant as long as you need to check for a small number of cases. If you have big array to check against, it would not be a suitable approach.

Community
  • 1
  • 1
codingadventures
  • 2,924
  • 2
  • 19
  • 36
  • This is **by far** the most elegant approach. Kudos and a heartfelt upvote! – Eugen Rieck Feb 19 '15 at 00:52
  • I personally don't appreciate boolean logic in CSharp; it just doesn't seem to fit with the coding style that I typically see in CSharp. However, I understand why other people appreciate this design pattern, but it just seems too low-level for me when CSharp provides Lists, Sets, and Arrays. – ManEatingCheese Feb 19 '15 at 00:54
  • 1
    @ManEatingCheese The flags translate into a simple bitwise operation - faster by orders of magnitude than anything, that arrays, lists or sets can provide, – Eugen Rieck Feb 19 '15 at 00:56
  • I will likely use enum flags because I really only had those 4 values to match. Thanks @JohnField. – IanK.CO Feb 19 '15 at 01:27
  • @IanK.CO you're welcome, I'm glad you found the solution helpful – codingadventures Feb 19 '15 at 01:40
  • @Eugen Rieck I've seen embedded code before and I know how these flags work. You are correct that this comparison is faster by orders of magnitudes compared to what an array search will cost. You may save ~2 nanoseconds every time you run with the flags. If this is a moderately trafficked piece of code (e.g. 3,000 hits per second) then you'll save about 1 second for every 2 days that your program runs. That's a performance boost of 0.001%. He's only going to notice performance gains if his code spends a significant amount of time in this function. – ManEatingCheese Feb 20 '15 at 20:38
  • @ManEatingCheese If your computer needs 2ns for an array search, **I want it** – Eugen Rieck Feb 20 '15 at 21:05
  • You caught me. I just did a rough test and it takes 50 ns for an array search or 1 ns for a binary and operation; I write code in a managed language so I'm not normally focused on such things. In my hypothetical he'd gain 25 seconds every 2 days. Again, performance gains for things like this are only seen if execution spends a significant amount of time in the function; otherwise readability and reliability are king. But of course, if developers find the bitwise operation intuitive and it's reliable (in my test it returned true for 0x11), then it's a keeper. – ManEatingCheese Feb 21 '15 at 19:19
  • 1
    I've put the code into practice now, I can't speak much to any performance difference (I didn't measure) between using enum flags and an int[]. But I can say that I like the readability of the code much much more for smaller operations instead of trying to remember what each integer in some array means when reading my code. A+ for an elegant, resource considerate, and repeatable solution that I can keep in my back pocket. – IanK.CO Mar 19 '15 at 21:14
2

See, I'm just thinking... why not use a switch?

https://msdn.microsoft.com/en-us/library/06tc147t.aspx

int myInt = 3;

switch (myInt)
{
case 0:
case 2:
case 3:
case 4:
    // Match
    break;
default:
    // No match
    break;
}
  • Well yeah maybe. I was really looking for an elegant shortcut is all I guess. – IanK.CO Feb 19 '15 at 00:34
  • 1
    Well, personally, I think switch is a very elegant construct. With fallthrough support and everything; it's quite a versatile construct to use if properly applied. –  Feb 19 '15 at 00:37
1

If your array is in order, Array.BinarySearch will be more efficient than Contains, especially if the array has more than a few elements.

if (Array.BinarySearch(checkArray, myInt) >= 0)
    ;//match
else
    ;//no match

Usually, however, the best choice for the Contains operation is the HashSet. Thanks to JohanLarsson for pointing that out.

phoog
  • 42,068
  • 6
  • 79
  • 117
  • Isn't HashSet the way to go if you want perf? – Johan Larsson Feb 19 '15 at 00:43
  • 1
    @JohanLarsson I think you are right. I was thinking that BinarySearch would make only one comparison if the value being tested was smaller than the smallest element or larger than the largest element, but that is not correct. – phoog Feb 19 '15 at 00:45
  • Very useful indeed. I may actually wind up checking the array this way, though Eugen's solution was more what I was after with the question. – IanK.CO Feb 19 '15 at 00:46
  • 1
    If your array has less than 10 elements, a simple Contains check will likely be faster. Definitely benchmark if you're concerned about performance. – Blorgbeard Feb 19 '15 at 00:47
  • 1
    @IanK.CO I have to say, though, that I would use the switch case, especially if the code's readability is hampered by removing the numbers from the method body. That might make it harder to understand what the code is doing. If you use the switch case, then the numbers are present in the method's code, as they would be using a series of `if` statements. – phoog Feb 19 '15 at 00:49
  • 1
    @Blorgbeard definitely. If performance is a concern, benchmarking is crucial. I would test Array.Contains (linear search) against BinarySearch and the HashSet to see what is fastest. – phoog Feb 19 '15 at 00:52
0

You could use a switch-case, but it could be argued that this looks messy.

switch (myInt)
{
    case 0: //Add a comment to make it clear that 
    case 2: //this is a deliberate fall-through and
    case 3: //not a mistake. (E.g. "//Deliberate
    case 4: //fall-through for 0, 2, 3, 4")

        //Insert code here in this section to do something
        Debug.WriteLine("Match");

        break; //Break statement is required to indicate end of section

    default:
        //The default section runs like an "else" statement
        //It is optional and will run if none of the above
        //cases are applicable.
        Debug.WriteLine("No Match");

        break;
} //end switch-case
Blorgbeard
  • 101,031
  • 48
  • 228
  • 272
ManEatingCheese
  • 228
  • 1
  • 11