как пройти через массив строк и применить функции для разных строк? - PullRequest
1 голос
/ 13 июня 2010

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

Я просматриваю файл и проверяю, какая строка в каждой строке, в зависимости от значения строкивыполнить другую функцию для него (или функций).

Вот как я это делаю сейчас:

Редактировать: Мне нужно использовать переменные вне if-else-Если диапазон внутри if, обновленный код:

string s1 = "used";
string s2 = "in";
string s3 = "functions";

if(str == "something"){
    something = process(s1, s2);
}else if(str == "something else"){
    something = process(s2, s3);
}else if(str == "something more"){
    something = process(s1, s3);
    something = process(s1, s2);
}else if(str == "something again"){
    // do more stuff
}else if(str == "something different"){
    // do more stuff
}else if(str == "something really different"){
    // do more stuff
}

Боюсь, это станет "медленным" после того, как мне придется повторять те, что еще, если строк много ...

Я пыталсяиспользуйте оператор switch (), но, очевидно, он здесь не работает, есть ли что-то похожее на switch () для использования здесь?

Ответы [ 4 ]

5 голосов
/ 13 июня 2010

Если вы просто хотите выполнять различные функции, вы можете использовать карту из строк для указателей функций или функторов, таких как boost::function / tr1::function:

void f1() { /* ... */ }
void f2() { /* ... */ }

// ... creating the map:
typedef void (*FuncPtr)();
typedef std::map<std::string, FuncPtr> FuncMap;
FuncMap fnMap;
fnMap["something"] = &f1;
fnMap["something else"] = &f2;

// ... using the map:
FuncMap::const_iterator it = fnMap.find(str);
if (it != fnMap.end()) { // is there an entry for str?
    it->second(); // call the function
}

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

void f1(const std::vector<std::string>& tokens) { /* ... */ }
// ...

typedef void (*FuncPtr)(const std::vector<std::string>&);
typedef std::map<std::string, FuncPtr> FuncMap;
// ...

std::vector<std::string> tokens = /* ...? */; 
FuncMap::const_iterator it = fnMap.find(str);
if (it != fnMap.end()) { 
    it->second(tokens); 
}

Вы также можете взглянуть на пример интерпретатора из Boost.FunctionTypes ( header , исходный файл ), похожий на ваш сценарий.

1 голос
/ 13 июня 2010

Во-первых, версия Георга с картой более элегантна и расширяема, чем длинный каскад сравнений.Однако, если вас интересует производительность и ваш «каскад» «медленный», измерьте, насколько он быстр.

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

void foo (const std::string& str, int (&count)[6]) 
{
    static const std::string s0 = "something";
    static const std::string s1 = "something else";
    static const std::string s2 = "something more";
    static const std::string s3 = "something again";
    static const std::string s4 = "something different";
    static const std::string s5 = "something really different";

    if(str == s0) {
        ++count[0];
    }else if(str == s1) {
        ++count[1];
    }else if(str == s2) {
        ++count[2];
    }else if(str == s3) {
        ++count[3];
    }else if(str == s4) {
        ++count[4];
    }else if(str == s5) {
        ++count[5];
    }
}

При использовании VS 2008 Express с настройками выпуска по умолчанию они выглядят так:

operator== with constant strings (the code above)

time 7.015 seconds
0.116917 microseconds per call

std::map lookup (Georg's code)

time 9.687 seconds
0.16145 microseconds per call

operator== with literal strings (original code)

time 10.437 seconds
0.17395 microseconds per call

Так что, если вы не будете много звонить по коду, вы не собираетесьобратите внимание на 174 наносекунды для вашей оригинальной версии.Предполагая, что карта и if-каскад ведут себя, как и ожидалось (O (N) и O (log 2 N)), тогда карта должна быть быстрее, примерно в 13 строках.Но если это так важно для вас, тогда оцените его или оцените.

0 голосов
/ 13 июня 2010

Я бы попробовал простую структуру данных, но, возможно, гуру C ++ и любители STL могли бы придумать что-нибудь лучше.Моя идея похожа на

struct smap {
  string s;
  int i;
} str_int_map[] = { { string("strng"), 1 }, /*...*/ };

, а затем

  j = 0; //default if no match found
  for(i=0; i < 2; i++)
  {
    if ( str_int_map[i].s == a ) 
    {
      j = str_int_map[i].i;
      break;
    }
  }
  switch( j )
  {
  case 1:
    cout << "oooo"; break;
  case 2:
    cout << "nnnn"; break;
  }

Вместо «сопоставления» с целым числом, вы можете «сопоставить» адрес функции и вызвать ее напрямую, если она соответствует вашемунужен такой подход.Вместо этого циклического подхода для сопоставления вы можете использовать реальную карту / словарь, независимо от того, что вызывается в STL, от строки к номеру, а затем включить этот номер, как в приведенном выше примере.

0 голосов
/ 13 июня 2010

Это должно быть наиболее эффективным. Но, может быть, оператор switch-case будет более элегантным?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...