1

How can you compare against multiple possibilities in one argument?

Example:

if ((integer == 2) || (integer == 5))

if ((string == "hello") || (string == "dolly))

Would save me a lot of code if you could write that like this:

if (integer == (2 || 5))

if (string == ("hello" || "dolly"))
Emil
  • 7,220
  • 17
  • 76
  • 135
  • 3
    Don't compare strings with "==" unless you *really* want that behavior. It may appear to work sometimes. See [How do I compare string in objective-c](http://stackoverflow.com/questions/1302985/how-do-i-compare-strings-in-objective-c). –  Oct 23 '10 at 21:45
  • 2
    pst, yeah, but in this particular case, I think we can look at this code as on a pseudocode, because this post looks like a philosophical and not a practical question :) – kovpas Oct 23 '10 at 21:52
  • also see http://stackoverflow.com/questions/3205065/ – sdcvvc Oct 23 '10 at 21:54
  • 1
    What you saved in typing you loose in confusing the next person that reads the code. Stop trying to be lazy and learn to type. – Martin York Oct 23 '10 at 22:54
  • Martin York, I'd say "and learn to copy-paste", as all these conditions could be easily copied and pasted :)) – kovpas Oct 24 '10 at 09:01
  • 1
    @kovpas: As a programmer, when you have to copy-paste, it means something is probably wrong with your algorithm, and if this happens often even for experts in the language, then something is seriously wrong with the language. The job of a language designer is to find a way to minimize the need for copy-paste-ing boilerplate codes. – Lie Ryan Oct 24 '10 at 21:08
  • @Lie Ryan: Sure, but what about the code in a topic? c/c++/java - any ways to avoid copy-paste, when you're comparing strings? – kovpas Oct 24 '10 at 22:33
  • @kovpas: You can write `indexOf(string s, string test[])`, which returns -1 if string s is not one of `test`, otherwise returns its index number. Then you just check for `indexOf(mys, {"abc", "def", "ghi", "jkl"}) != -1`. If your language supports concise functional style-programming, you can write `(any ("abc" ==) ["abc", "def", "ghi"])`. The best languages though, have an `in` operator: `s in ("abc", "def", "ghi")`. – Lie Ryan Oct 25 '10 at 08:57
  • @kovpas: These may initially appear more complex than using chained `||`s, but there is no DRY issue; it's your job as a programmer whether to sacrifice either DRY or complexity. However, if your programming language forces you to make these sort of sacrifices a lot, then you can suspect that there is something wrong with either the language design or you're missing a language idiom/feature that could make your life better. – Lie Ryan Oct 25 '10 at 09:04
  • @Lie Ryan: At first, a job any programmer is to write a human-readable code. In your example "indexOf(...)" is less readable, than "if (a || b)" for vast majority of programmers. – kovpas Oct 25 '10 at 09:23
  • 1
    @kovpas: `if (a || b)` is solving a different problem, there is no repetition in that. But there is a repetition in the code that is both uglier than indexOf and violates DRY: `if (mystr == "abc" || mystr == "def" || mystr == "ghi")`. – Lie Ryan Oct 25 '10 at 11:10
  • @Lie Ryan: IMO, indexOf is less readable, than "if (mystr == "abc" || mystr == "def" || mystr == "ghi")". I think it's really subjective thing, so I suggest to stop at this point :) – kovpas Oct 25 '10 at 12:33

7 Answers7

11

First of all string comparasion doesn't work that way in C, I know nothing about objective-c, thought.

For the comparison against compile time integral constants, in C you have the switch statement:

switch (integer) {
case 2: ;
case 5: ;
   /* do stuff here */
}
Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
7

Actually, you can check if NSSet contains some object. This won't work with int, as it's not an object, but will work with NSString.

I believe it could be written like this:

if ( [[NSSet setWithObjects:@"hello", @"dolly", nil] containsObject:string] )

So, if you want to compare ints, you should wrap them with NSNumber.

This won't save a lot of code if you are not comparing tens of objects, but this looks pretty similar to what you want to get :)

UPDATE:

Or another way (quite similar to the answer from John Calsbeek, but works for multiple arguments):

@implementation NSObject (IsEqualMultiple)

- (BOOL)isEqualToOneOfObjects:(id)firstObject, ... {
    id eachObject;
    va_list argumentList;

    if (firstObject) {
        if ( [self isEqual:firstObject] ) return YES;

        va_start(argumentList, firstObject);

        while (eachObject = va_arg(argumentList, id))
            if ( [self isEqual:eachObject] ) return YES;
        va_end(argumentList);
    }

    return NO;
}

@end

Usage:

if ( [string isEqualToOneOfObjects:@"hello", @"dolly", @"this", @"is", @"Louis", nil] )
Community
  • 1
  • 1
kovpas
  • 9,553
  • 6
  • 40
  • 44
3

If you wanted to do this with an object type, like say NSString, and you feel comfortable with categories, you could do add a category method:

@implementation NSObject (IsEqualMultiple)

- (BOOL)isEqualTo:(id)obj1 or:(id)obj2 
{
    return [self isEqual:obj1] || [self isEqual:obj2];
}

@end

Then you could use it like this:

if ([string isEqualTo:@"hello" or:@"dolly"])
John Calsbeek
  • 35,947
  • 7
  • 94
  • 101
2

This isn't part of the language. If you really want to avoid the typing, you could just create a function to do it, something along the lines of:

int intIsIn (int needle, int *haystack, size_t sz);
:
if (intIsIn (integer, {2,5}, 2)) ...

(and similar for other data types). I question the usefulness of this approach however because (1) it's only less typing for longer lists; and (2) you'll probably end up on "The Daily WTF" :-)

My opinion would be to just suck it up, it's not really that much typing.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1

Create a variadic function or one that receives an array of strings for the comparison.

Fernando
  • 4,029
  • 1
  • 26
  • 35
0

If your integers are nonzero and small enough to fit in unsigned char or wchar_t, a convenient way to do this is something like:

if (strchr("\2\5", integer)) ...

or:

if (wcschr(L"\2\5", integer)) ...

Keep in mind those are octal values, not decimal. You could use hex (\x) if you prefer.

For strings, the way to make it efficient is to use a regular expression, or write your own DFA to accept the set of strings you want to test for.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
0

At first, you should remember that good compiler should optimize multiple comparisons if it can draw conclusions about them, for example if value is compared through set of literals. So there's no need to 'optimize' expressions like x==1 || x==3 || x==7 by hand.

In C, works for integers in range 0..31 (or thich bits have your long, but you may use long long instead)

if(((1UL<<val1)|(1UL<<val2)|(1UL<<val3)) & (1UL<<x)) ...

This creates number having ones in bits corresponding to values should evaluate to true. It is convenient if you need to compare with variable list of small integers.

You may also use sorted array of values and c standard function bsearch():

int valuelist[] = { /* note it sorted */
    2, 5, 17, 33, 99, 103, 808
}

int valuelist_length = sizeof(valuelist)/sizeof(int);
/* this works only for statically allocated non-external arrays, */
/* you may need another method of evaluating number of items */

int compar_int(const void *a, const void *b) {
    return ((const int *)b < (const int *)a) - ((const int *)a < (const int *)b);
}
...

if(bsearch(&x, valuelist, sizeof(int), valuelist_length, compar_int)) {
    /* bsearch returns pointer to found value or NULL if it is not found */
    /* so it will be evaluated as true if value exists in array */
}

But this is efficient only if you have really many numbers to compare.

Vovanium
  • 3,798
  • 17
  • 23