Как Вы сделали бы этот оператор переключения максимально быстро?

Это - специальная таблица в Oracle. Я часто использую его для вычислений или проверяющий системные переменные. Например:

  • Select 2*4 from dual распечатывает результат вычисления
  • Select sysdate from dual печать текущая дата сервера.
33
задан 6 revs, 2 users 100% 3 May 2012 в 05:47
поделиться

20 ответов

Предполагая, что каждый ввод будет действительным ActivCode , вы можете изменить значения перечисления и сильно связаны с реализацией GetHashCode :

enum MarketDataExchange
{
    NONE,
    NBBO = 371857150,
    AMEX = 372029405,
    BSE = 372029408,
    BATS = -1850320644,
    NSE = 372029407,
    CHX = -284236702,
    NYSE = 372029412,
    ARCA = -734575383,
    NASDAQ = 372029421,
    NASDAQ_ADF = -1137859911,
    CBOE = 372029419,
    PHLX = 372029430,
    DIRECTEDGE = 372029429
}

public static MarketDataExchange GetMarketDataExchange(string ActivCode)
{
    if (ActivCode == null) return MarketDataExchange.NONE;

    return (MarketDataExchange)ActivCode.GetHashCode();
}
26
ответ дан 27 November 2019 в 17:37
поделиться

Я бы использовал свою собственную быструю хеш-функцию и использовал оператор целочисленного переключения, чтобы избежать сравнения строк:

int  h = 0;  

// Compute fast hash: A[0] + A[1]*0x100
if (ActivCode.Length > 0)
    h += (int) ActivCode[0];
if (ActivCode.Length > 1)
    h += (int) ActivCode[1] << 8;  

// Find a match
switch (h)
{
    case 0x0000:  return MarketDataExchange.NBBO;        // ""
    case 0x0041:  return MarketDataExchange.AMEX;        // "A"
    case 0x0042:  return MarketDataExchange.BSE;         // "B"
    case 0x5442:  return MarketDataExchange.BATS;        // "BT"
    case 0x0043:  return MarketDataExchange.NSE;         // "C"
    case 0x574D:  return MarketDataExchange.CHX;         // "MW"
    case 0x004E:  return MarketDataExchange.NYSE;        // "N"
    case 0x4150:  return MarketDataExchange.ARCA;        // "PA"
    case 0x0051:  return MarketDataExchange.NASDAQ;      // "Q"
    case 0x4451:  return MarketDataExchange.NASDAQ_ADF;  // "QD"
    case 0x0057:  return MarketDataExchange.CBOE;        // "W"
    case 0x0058:  return MarketDataExchange.PHLX;        // "X"
    case 0x0059:  return MarketDataExchange.DIRECTEDGE;  // "Y"
    default:      return MarketDataExchange.NONE;
}

Мои тесты показывают, что это примерно в 4,5 раза быстрее , чем исходный код.

Если бы в C # был препроцессор, я бы использовал макрос для формирования констант case.

Этот метод быстрее, чем использование хеш-таблицы, и, конечно, быстрее, чем использование сравнения строк. Он работает для строк длиной до четырех символов с 32-битными целыми числами и до 8 символов с использованием 64-битных длинных чисел.

21
ответ дан 27 November 2019 в 17:37
поделиться

Можно ли преобразовать ActivCode в int, а затем использовать int в наших операторах case?

0
ответ дан 27 November 2019 в 17:37
поделиться

Пара случайных мыслей, которые могут быть неприменимы вместе:

Включите первый символ в строке, а не саму строку, и выполните вспомогательный переключатель для строк, которые могут содержать более одной буквы. ?

Хеш-таблица, безусловно, гарантирует получение O (1), хотя это может быть не быстрее при меньшем количестве сравнений.

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

И если вам действительно нужно, чтобы это было как можно быстрее, почему вы не пишете это на ассемблере? :)

0
ответ дан 27 November 2019 в 17:37
поделиться

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

Но я согласен с Клетусом: лучшее ускорение, которое я могу придумать, - это использовать хэш-карту с большим количеством места (чтобы не было коллизий).

0
ответ дан 27 November 2019 в 17:37
поделиться

Поместите наблюдения в отсортированную структуру с нелинейным доступом (например, хеш-таблицу). У вашего переключателя будет линейное время.

0
ответ дан 27 November 2019 в 17:37
поделиться

Все ваши строки состоят не более чем из 2 символов и ASCII, поэтому мы можем использовать 1 байт на символ. Более того, более вероятно, что в них никогда не может появиться \ 0 (.NET string допускает встроенные нулевые символы, но многие другие вещи - нет). Исходя из этого предположения, мы можем обнулить все ваши строки так, чтобы каждая строка составляла ровно 2 байта, или ushort :

""   -> (byte) 0 , (byte) 0   -> (ushort)0x0000
"A"  -> (byte)'A', (byte) 0   -> (ushort)0x0041
"B"  -> (byte)'B', (byte) 0   -> (ushort)0x0042
"BT" -> (byte)'B', (byte)'T'  -> (ushort)0x5442

Теперь, когда у нас есть одно целое число в относительно (64К) коротком диапазоне, мы можем используйте таблицу поиска:

MarketDataExchange[] lookup = {
    MarketDataExchange.NBBO, 
    MarketDataExchange.NONE, 
    MarketDataExchange.NONE, 
    ...
    /* at index 0x041 */
    MarketDataExchange.AMEX,
    MarketDataExchange.BSE,
    MarketDataExchange.NSE,
    ...
};

Теперь, получение значения данной строки:

public static unsafe MarketDataExchange GetMarketDataExchange(string s)
{
   // Assume valid input
   if (s.Length == 0) return MarketDataExchange.NBBO;

   // .NET strings always have '\0' after end of data - abuse that
   // to avoid extra checks for 1-char strings. Skip index checks as well.
   ushort hash;
   fixed (char* data = s)
   {
       hash = (ushort)data[0] | ((ushort)data[1] << 8);
   }

   return lookup[hash];
}
1
ответ дан 27 November 2019 в 17:37
поделиться

Беспорядочно, но использование комбинации вложенных if и жесткого кодирования может просто превзойти оптимизатор: -

   if (ActivCode < "N") {
         // "" to "MW"
         if (ActiveCode < "BT") {
            // "" to "B"
            if (ActiveCode < "B") {
                // "" or "A"
                if (ActiveCode < "A") {
                      // must be ""
                     retrun MarketDataExchange.NBBO;
                } else {
                     // must be "A"
                    return MarketDataExchange.AMEX;
                }
            } else {
                // must be "B"
                return MarketDataExchange.BSE;
            }
         } else {
            // "BT" to "MW"
            if (ActiveCode < "MW") {
                // "BT" or "C"
                if (ActiveCode < "C") {
                      // must be "BT"
                     retrun MarketDataExchange.NBBO;
                } else {
                     // must be "C"
                    return MarketDataExchange.NSE;
                }
            } else {
            // must be "MV"
                return MarketDataExchange.CHX;
            }
         }
    } else {
        // "N" TO "Y"
         if (ActiveCode < "QD") {
            // "N" to "Q"
            if (ActiveCode < "Q") {
                // "N" or "PA"
                if (ActiveCode < "PA") {
                      // must be "N"
                     retrun MarketDataExchange.NYSE;
                } else {
                     // must be "PA"
                    return MarketDataExchange.ARCA;
                }
            } else {
                // must be "Q"
                return MarketDataExchange.NASDAQ;
            }
         } else {
            // "QD" to "Y"
            if (ActiveCode < "X") {
                // "QD" or "W"
                if (ActiveCode < "W") {
                      // must be "QD"
                     retrun MarketDataExchange.NASDAQ_ADF;
                } else {
                     // must be "W"
                    return MarketDataExchange.CBOE;
                }
            } else {
            // "X" or "Y"
                if (ActiveCode < "Y") {
                      // must be "X"
                     retrun MarketDataExchange.PHLX;
                } else {
                     // must be "Y"
                    return MarketDataExchange.DIRECTEDGE;
                }
            }
         }
    }

Это дает правильную функцию с тремя или четырьмя сравнениями. Я бы даже не подумал сделать это по-настоящему, если не ожидается, что ваш фрагмент кода будет выполняться несколько раз в секунду!

Вы также оптимизируете его так, чтобы выполнялось сравнение только одного символа. например, замените '<"BT"' на '> = "B"' - хоть немного быстрее и еще хуже читается!

1
ответ дан 27 November 2019 в 17:37
поделиться

+1 за использование словаря. Не обязательно для оптимизации, но это было бы чище.

Я бы, вероятно, использовал константы и для строк, хотя сомневаюсь, что это принесет вам что-нибудь с точки зрения производительности.

1
ответ дан 27 November 2019 в 17:37
поделиться

Если значения перечисления произвольны, вы можете сделать это ...

public static MarketDataExchange GetValue(string input)
{
    switch (input.Length)
    {
        case 0: return MarketDataExchange.NBBO;
        case 1: return (MarketDataExchange)input[0];
        case 2: return (MarketDataExchange)(input[0] << 8 | input[1]);
        default: return MarketDataExchange.None;
    }
}

... если вы хотите сойти с ума, вы также можете использовать небезопасный вызов с указателями, как заметил Павел Минаев ... Версия с чистым приведением выше быстрее, чем эта небезопасная версия.

unsafe static MarketDataExchange GetValue(string input)
{
    if (input.Length == 1)
        return (MarketDataExchange)(input[0]);
    fixed (char* buffer = input)
        return (MarketDataExchange)(buffer[0] << 8 | buffer[1]);
}

public enum MarketDataExchange
{
    NBBO = 0x00, //
    AMEX = 0x41, //A
    BSE = 0x42, //B
    BATS = 0x4254, //BT
    NSE = 0x43, //C
    CHX = 0x4D57, //MW
    NYSE = 0x4E, //N
    ARCA = 0x5041, //PA
    NASDAQ = 0x51, //Q
    NASDAQ_ADF = 0x5144, //QD
    CBOE = 0x57, //W
    PHLX = 0x58, //X
    DIRECTEDGE = 0x59, //Y

    None = -1
}
2
ответ дан 27 November 2019 в 17:37
поделиться

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

public class Service 
{
    public static MarketDataExchange GetMarketDataExchange(string ActivCode) {
    {
        int x = 65, y = 65;
        switch(ActivCode.Length)
        {
            case 1:
                x = ActivCode[0];
                break;
            case 2:
                x = ActivCode[0];
                y = ActivCode[1];
                break;
        }
        return _table[x, y];
    }

    static Service()
    {
        InitTable();
    }

    public static MarketDataExchange[,] _table = 
        new MarketDataExchange['Z','Z'];

    public static void InitTable()
    {
        for (int x = 0; x < 'Z'; x++)
            for (int y = 0; y < 'Z'; y++)
                _table[x, y] = MarketDataExchange.NONE;

        SetCell("", MarketDataExchange.NBBO);
        SetCell("A", MarketDataExchange.AMEX);
        SetCell("B", MarketDataExchange.BSE);
        SetCell("BT", MarketDataExchange.BATS);
        SetCell("C", MarketDataExchange.NSE);
        SetCell("MW", MarketDataExchange.CHX);
        SetCell("N", MarketDataExchange.NYSE);
        SetCell("PA", MarketDataExchange.ARCA);
        SetCell("Q", MarketDataExchange.NASDAQ);
        SetCell("QD", MarketDataExchange.NASDAQ_ADF);
        SetCell("W", MarketDataExchange.CBOE);
        SetCell("X", MarketDataExchange.PHLX);
        SetCell("Y", MarketDataExchange.DIRECTEDGE);
    }

    private static void SetCell(string s, MarketDataExchange exchange)
    {
        char x = 'A', y = 'A';
        switch(s.Length)
        {
            case 1:
                x = s[0];
                break;
            case 2:
                x = s[0];
                y = s[1];
                break;
        }
        _table[x, y] = exchange;
    }
}

Сделайте перечисление на основе байтов, чтобы сэкономить немного места.

public enum MarketDataExchange : byte
{
    NBBO, AMEX, BSE, BATS, NSE, CHX, NYSE, ARCA, 
    NASDAQ, NASDAQ_ADF, CBOE, PHLIX, DIRECTEDGE, NONE
}
3
ответ дан 27 November 2019 в 17:37
поделиться

Я бы поместил его в словарь вместо использования оператора switch. При этом, возможно, это не имеет значения. Или может. См. Ограничения оператора переключения C # - почему? .

3
ответ дан 27 November 2019 в 17:37
поделиться

Простите меня, если я ошибаюсь, я экстраполирую свои знания C ++. Например, если вы возьмете ActivCode [0] пустой строки, в C ++ вы получите символ, значение которого равно нулю.

Создайте двумерный массив, который вы инициализируете один раз; первое измерение - это длина кода, второе - символьное значение. Введите значение перечисления, которое вы хотите вернуть. Теперь вся ваша функция выглядит так:

public static MarketDataExchange GetMarketDataExchange(string ActivCode) {
    return LookupTable[ActivCode.Length][ActivCode[0]];
}

К счастью для вас, все двухсимвольные коды уникальны в первой букве по сравнению с другими двухсимвольными кодами.

4
ответ дан 27 November 2019 в 17:37
поделиться

Я бы экстраполировал ответ tster на «переключить пользовательскую хеш-функцию», предполагая что генератор кода создает таблицу поиска или - в противном случае - сам создает таблицу поиска.

Пользовательская хеш-функция должна быть простой, например:

(int)ActivCode[0]*2 + ActivCode.Length-1

Для этого потребуется таблица из 51 элемента, легко хранимая в кэше L1 , при следующих предположениях:

  • Входные данные должны быть уже проверены
  • пустая строка должна обрабатываться отдельно
  • двухсимвольные коды не начинаются с одного и того же символа
  • добавление новых случаев сложно

пустая строка case можно было бы включить, если бы вы могли использовать небезопасный доступ к ActivCode [0] , давая знак конца '\ 0'.

4
ответ дан 27 November 2019 в 17:37
поделиться

Измените переключатель, чтобы включить HashCode () строк.

4
ответ дан 27 November 2019 в 17:37
поделиться

При допустимом вводе можно использовать

if (ActivCode.Length == 0)
    return MarketDataExchange.NBBO;

if (ActivCode.Length == 1)
    return (MarketDataExchange) (ActivCode[0]);

return (MarketDataExchange) (ActivCode[0] | ActivCode[1] << 8);
5
ответ дан 27 November 2019 в 17:37
поделиться

Есть ли у вас какие-либо статистические данные о том, какие строки встречаются чаще? Чтобы их можно было проверить в первую очередь?

5
ответ дан 27 November 2019 в 17:37
поделиться

Я бы использовал словарь для пар ключ-значение и воспользовался бы временем поиска O (1).

6
ответ дан 27 November 2019 в 17:37
поделиться

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

Предполагая, что ActivCode всегда действителен, конечно, ускорит процесс. Вам не нужно проверять наличие null или пустой строки, и вы можете оставить один тест с конца переключателя. То есть проверьте все, кроме Y, а затем верните DIRECTEDGE, если совпадение не найдено.

Вместо того, чтобы включать всю строку, включите ее первую букву. Для кодов с большим количеством букв поместите второй тест внутри корпуса переключателя. Примерно так:

switch(ActivCode[0])
{
   //etc.
   case 'B':
      if ( ActivCode.Length == 1 ) return MarketDataExchange.BSE; 
      else return MarketDataExchange.BATS;
      // etc.
}

Было бы лучше, если бы вы могли вернуться и изменить коды так, чтобы они были одиночными символами, потому что тогда вам никогда не понадобится больше одного теста. Еще лучше было бы использовать числовое значение перечисления, чтобы вы могли просто преобразовать, вместо того, чтобы переключать / переводить в первую очередь.

Вам не нужно проверять наличие null или пустой строки, и вы можете оставить один тест с конца переключателя. То есть проверьте все, кроме Y, а затем верните DIRECTEDGE, если совпадение не найдено.

Вместо того, чтобы включать всю строку, включите ее первую букву. Для кодов с большим количеством букв поместите второй тест внутри корпуса переключателя. Примерно так:

switch(ActivCode[0])
{
   //etc.
   case 'B':
      if ( ActivCode.Length == 1 ) return MarketDataExchange.BSE; 
      else return MarketDataExchange.BATS;
      // etc.
}

Было бы лучше, если бы вы могли вернуться и изменить коды так, чтобы они были одиночными символами, потому что тогда вам никогда не понадобится больше одного теста. Еще лучше было бы использовать числовое значение перечисления, чтобы вы могли просто преобразовать, вместо того, чтобы переключать / переводить в первую очередь.

Вам не нужно проверять наличие null или пустой строки, и вы можете оставить один тест с конца переключателя. То есть проверьте все, кроме Y, а затем верните DIRECTEDGE, если совпадение не найдено.

Вместо того, чтобы включать всю строку, включите ее первую букву. Для кодов с большим количеством букв поместите второй тест внутри корпуса переключателя. Примерно так:

switch(ActivCode[0])
{
   //etc.
   case 'B':
      if ( ActivCode.Length == 1 ) return MarketDataExchange.BSE; 
      else return MarketDataExchange.BATS;
      // etc.
}

Было бы лучше, если бы вы могли вернуться и изменить коды, чтобы все они были одиночными символами, потому что тогда вам никогда не понадобится больше одного теста. Еще лучше было бы использовать числовое значение перечисления, чтобы вы могли просто преобразовать, вместо того, чтобы переключать / переводить в первую очередь.

а затем вернуть DIRECTEDGE, если совпадений не найдено.

Вместо включения всей строки, включите ее первую букву. Для кодов с большим количеством букв проведите второй тест внутри корпуса переключателя. Примерно так:

switch(ActivCode[0])
{
   //etc.
   case 'B':
      if ( ActivCode.Length == 1 ) return MarketDataExchange.BSE; 
      else return MarketDataExchange.BATS;
      // etc.
}

Было бы лучше, если бы вы могли вернуться и изменить коды, чтобы все они были одиночными символами, потому что тогда вам никогда не понадобится больше одного теста. Еще лучше было бы использовать числовое значение перечисления, чтобы вы могли просто преобразовать, вместо того, чтобы переключать / переводить в первую очередь.

а затем вернуть DIRECTEDGE, если совпадение не найдено.

Вместо включения всей строки, включите ее первую букву. Для кодов с большим количеством букв поместите второй тест внутри корпуса переключателя. Примерно так:

switch(ActivCode[0])
{
   //etc.
   case 'B':
      if ( ActivCode.Length == 1 ) return MarketDataExchange.BSE; 
      else return MarketDataExchange.BATS;
      // etc.
}

Было бы лучше, если бы вы могли вернуться и изменить коды так, чтобы они были одиночными символами, потому что тогда вам никогда не понадобится больше одного теста. Еще лучше было бы использовать числовое значение перечисления, чтобы вы могли просто преобразовать, вместо того, чтобы переключать / переводить в первую очередь.

потому что тогда вам никогда не понадобится больше одного теста. Еще лучше было бы использовать числовое значение перечисления, чтобы вы могли просто преобразовать, вместо того, чтобы переключать / переводить в первую очередь.

потому что тогда вам никогда не понадобится больше одного теста. Еще лучше было бы использовать числовое значение перечисления, чтобы вы могли просто преобразовать, вместо того, чтобы переключать / переводить в первую очередь.

8
ответ дан 27 November 2019 в 17:37
поделиться
  1. Избегать всех сравнений строк.
  2. Избегайте просмотра более чем одного символа (когда-либо)
  3. Избегайте if-else, поскольку я хочу, чтобы компилятор мог оптимизировать как можно лучше
  4. Попытайтесь получить результат одним прыжком переключателя

код:

public static MarketDataExchange GetMarketDataExchange(string ActivCode) {
    if (ActivCode == null) return MarketDataExchange.NONE;
    int length = ActivCode.Length;
    if (length == 0) return MarketDataExchange.NBBO;

    switch (ActivCode[0]) {
        case 'A': return MarketDataExchange.AMEX;
        case 'B': return (length == 2) ? MarketDataExchange.BATS : MarketDataExchange.BSE;
        case 'C': return MarketDataExchange.NSE;
        case 'M': return MarketDataExchange.CHX;
        case 'N': return MarketDataExchange.NYSE;
        case 'P': return MarketDataExchange.ARCA;
        case 'Q': return (length == 2) ? MarketDataExchange.NASDAQ_ADF : MarketDataExchange.NASDAQ;
        case 'W': return MarketDataExchange.CBOE;
        case 'X': return MarketDataExchange.PHLX;
        case 'Y': return MarketDataExchange.DIRECTEDGE;
        default:  return MarketDataExchange.NONE;
    }
}
3
ответ дан 27 November 2019 в 17:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: