Есть ли более элегантное решение для большого оператора switch? - PullRequest
1 голос
/ 30 марта 2012

Я получил карту многих диапазонов для значения, такого как 0-300 = 10, 300-600 = 20, 600-900 = 30 ... 2500000-2700000 = 7000 .... Так что я мог бы сделать действительно большой оператор switch / if-block, но мне интересно, есть ли более элегантный подход для решения этой маленькой проблемы.

Хорошо, вот небольшое подмножество таблицы с реальными данными:

0-300 : 25
301-600.  : 45
601-900 : 65
901-1200. : 85
1201-1500: 105

1501-2000 : 133
2001-2500 : 161
2501-3000: 189
3001-3500:217
3501-4000:245

4001-4500:273
4501-5000:301
5001-6000:338

Ответы [ 3 ]

5 голосов
/ 30 марта 2012

Самым распространенным способом избавления от оператора switch является использование словаря.В вашем случае, поскольку вы отображаете диапазоны, вместо этого вы будете использовать NSArray срезов диапазона.Вот как это выглядело бы, если бы вы имели дело с целыми числами:

NSArray *rangeCutoffs = [NSArray arrayWithObjects:[NSNumber numberWithInt:300],[NSNumberWithInt:600],...,nil];
NSArray *values = [NSArray arrayWithObjects:[NSNumber numberWithInt:10], [NSNumber numberWithInt:20],...,nil];

int mappedInt;
for (int index=0; index <= [rangeCutoffs count]; index++) {
    if (intToMap < [[rangeCutoffs objectAtIndex:index] intValue]) {
        mappedInt = [[values objectAtIndex:index] intValue];
    }
}
if (mappedInt == 0) {
    mappedInt = [[values lastObject] intValue];
}

На практике вы хотите загрузить rangeCutoffs и values из списков вместо их жесткого кодирования.

1 голос
/ 30 марта 2012

Вы можете использовать таблицу.например,

struct Lookup
{
    int min;
    int max;
    int value;
};

struct Lookup table[] =
{
    {       0,     300,   10 },
    {     301,     600,   20 },
    {     601,     900,   30 },
    // other ranges
    { 2500000, 2700000, 7000 },
    { -1, -1, -1 } // marks the end of the table
};

А затем просто итерировать по нему, чтобы найти правильный диапазон

int result = -1;
for (int i = 0 ; table[i].min != -1 && result == -1 ; ++i)
{
     if (table[i].min <= value && value <= table[i].max)
     {
         result = table[i].value;
     }
}

Если это действительно большая таблица, вы можете использовать вместо этого бинарный поиск.

0 голосов
/ 30 марта 2012

Вы можете сделать что-то вроде этого (пример C):

#include <stdio.h>
#include <stdlib.h>

typedef int range_type;
typedef int value_type;

typedef struct {
    range_type min;
    range_type max;
    value_type value;
} range_t;

const range_t *find_range(const range_t *ranges, size_t rangesSize,
    value_type valueToFind)
{
    for (size_t i = 0; i < rangesSize; ++i) {
        if (ranges[i].min <= valueToFind && valueToFind <= ranges[i].max)
            return &ranges[i];
    }
    return NULL;
}

int main() {
    const range_t ranges[] = {
        {   0,  300, 10 },
        { 301,  600, 20 },
        { 601,  900, 30 },
        { 901, 1200, 40 }
        // And so on...
    };

    value_type testValues[] = {
          -1,                   // None
           0, 299,  300,    // [  0,  300]
         301, 599,  600,    // [301,  600]
         601, 899,  900,    // [601,  900]
         901, 1199, 1200,   // [901, 1200]
         // And so on...
    };

    for (size_t i = 0; i < sizeof(testValues) / sizeof(testValues[0]); ++i) {
        const range_t *match = find_range(
            ranges, sizeof(ranges) / sizeof(ranges[0]), testValues[i]);
        if (match != NULL)
            printf("%d found at [%d..%d]\n", testValues[i], match->min,
                match->max);
        else
            printf("%d not found\n", testValues[i]);
    }
    return EXIT_SUCCESS;
}

Должен вывести:

-1 not found
0 found at [0..300]
299 found at [0..300]
300 found at [0..300]
301 found at [301..600]
599 found at [301..600]
600 found at [301..600]
601 found at [601..900]
899 found at [601..900]
900 found at [601..900]
901 found at [901..1200]
1199 found at [901..1200]
1200 found at [901..1200]
...