Более быстрый оператор if: if `variable` равен« value »или« value » - PullRequest
1 голос
/ 24 октября 2010

Как вы можете сравнить несколько вариантов в одном аргументе?

Пример:

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

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

Спас бы меня много кода, если бы вы могли написать так:

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

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

Ответы [ 7 ]

11 голосов
/ 24 октября 2010

Прежде всего, сравнение строк не работает таким образом в C, я ничего не знаю о target-c, подумал.

Для сравнения с интегральными константами времени компиляции в C у вас есть оператор switch:

switch (integer) {
case 2: ;
case 5: ;
   /* do stuff here */
}
7 голосов
/ 24 октября 2010

На самом деле, вы можете проверить, содержит ли NSSet какой-либо объект.Это не будет работать с int, так как это не объект, но будет работать с NSString.

Я думаю, это можно написать так:

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

Итак, если вы хотитесравните целые числа, вы должны обернуть их с помощью NSNumber.

Это не сэкономит много кода, если вы не сравниваете десятки объектов, но это выглядит очень похоже на то, что вы хотите получить:)

ОБНОВЛЕНИЕ:

Или другим способом (очень похожим на ответ Джона Калсбека , но работает для нескольких аргументов):

@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

Использование:

if ( [string isEqualToOneOfObjects:@"hello", @"dolly", @"this", @"is", @"Louis", nil] )
3 голосов
/ 24 октября 2010

Если вы хотите сделать это с типом объекта, например, скажем NSString, и вы чувствуете себя комфортно с категориями, вы можете добавить метод категории:

@implementation NSObject (IsEqualMultiple)

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

@end

Тогда вы можете использовать это так:

if ([string isEqualTo:@"hello" or:@"dolly"])
2 голосов
/ 24 октября 2010

Это не часть языка. Если вы действительно хотите избежать ввода, вы можете просто создать для этого функцию, что-то вроде:

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

(и аналогично для других типов данных). Я подвергаю сомнению полезность этого подхода, потому что (1) он только меньше печатает для более длинных списков; и (2) вы, вероятно, окажетесь на "The Daily WTF" : -)

Мое мнение было бы просто смириться с этим, на самом деле не , что много печатает.

1 голос
/ 24 октября 2010

Создайте переменную или функцию, которая получает массив строк для сравнения.

0 голосов
/ 25 октября 2010

Сначала вы должны помнить, что хороший компилятор должен оптимизировать множественные сравнения, если он может сделать выводы о них, например, если значение сравнивается с помощью набора литералов.Таким образом, нет необходимости «оптимизировать» выражения типа x == 1 ||х == 3 ||x == 7 от руки.

В C работает для целых чисел в диапазоне 0..31 (или у этих битов есть long, но вместо этого вы можете использовать long long)

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

Это создает число, имеющее единицы в битах, соответствующие значениям, которые должны принимать значение true.Это удобно, если вам нужно сравнить со списком переменных маленькие целые числа.

Вы также можете использовать отсортированный массив значений и стандартную функцию c 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 */
}

Но это эффективнотолько если у вас действительно много чисел для сравнения.

0 голосов
/ 24 октября 2010

Если ваши целые числа отличны от нуля и достаточно малы, чтобы поместиться в unsigned char или wchar_t, удобный способ сделать это что-то вроде:

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

или

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

Имейте в виду, что это восьмеричные значения, а не десятичные. Вы можете использовать гекс (\x), если хотите.

Для строк способ сделать это эффективным - использовать регулярное выражение или написать собственный DFA, чтобы принять набор строк, для которых вы хотите проверить.

...