2013-06-19 5 views
2

Привет, у меня есть std::vector<std::string>, содержащие даты, такие как 2011-03-23T12:23:32.123 из этого, я хотел бы gen '2 векторов int20110323 и 122332123.Как я могу ускорить эту операцию STL?

Я использую C++ библиотеку под названием Rcpp (это на самом деле не проблема здесь, я думаю, но вы никогда не знаете, так что я поставил Rcpp тега)

Я сделал это, который делает работу, но это довольно медленно, как могу ли я ускорить это?

Rcpp::List datetimeToInt(vector<string> datetimes){ 

    const int N=datetimes.size(); 
    Rcpp::IntegerVector date(N); //please consider those as std::vector<int> 
    Rcpp::IntegerVector time(N); 

    //this is what I want to speed up 
    for(int i=0; i<N; ++i){ 
     datetimes[i].erase(std::remove_if(datetimes[i].begin(), datetimes[i].end(), not1(ptr_fun(::isdigit))), datetimes[i].end()); 
     date[i] = atoi(datetimes[i].substr(0,8).c_str()); 
     time[i] = atoi(datetimes[i].substr(8,12).c_str()); 
    } 

    return Rcpp::List::create(_["date"]=date, _["time"]=time); 
} 
+0

Какие параметры компилятора вы используете? – jtomaszk

+0

'-std = C++ 0x -O2 -Wall -mtune = core2 -c', но я больше ищу' алгоритмический/stl malpractice' ответ – statquant

ответ

1

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

datetimes[i].erase(std::remove_if(datetimes[i].begin(), datetimes[i].end(), not1(ptr_fun(::isdigit))), datetimes[i].end()); 
    date[i] = atoi(datetimes[i].substr(0,8).c_str()); 
    time[i] = atoi(datetimes[i].substr(8,12).c_str()); 

с чем-то более сложным и оптимизированной, например смт, как это (но я не проверял он):

int dateId = 0; 
int timeId = 0; 
char time_c[9]; 
char date_c[8]; 

for (int strId = 0; i < str.length(); ++strId) { 
    if (isdigit(datetimes[i][strId]) { 
     if (dateId >= 8) { 
      time_c[timeId] = datetimes[i][strId]; 
      ++timeId; 
     } else { 
      date_c[dateId] = datetimes[i][strId]; 
      ++dateId; 
     } 
    } 
} 

date[i] = atoi(date_c); 
time[i] = atoi(time_c); 

он разбивает строку на две части только в одном проходе

1

Использование std::vector<std::string>, мы должны сделать копию строк. Это пустая трата времени. Вы должны использовать CharacterVector, который не должен делать копии при работе непосредственно с данными.

// [[Rcpp::export]] 
List datetimeToInt2(CharacterVector datetimes){ 

    const int N=datetimes.size(); 
    IntegerVector date(N); 
    IntegerVector time(N); 
    std::string current ; 

    //this is what I want to speed up 
    for(int i=0; i<N; ++i){ 
     current = datetimes[i] ; 
     current.erase(std::remove_if(current.begin(), current.end(), std::not1(std::ptr_fun(::isdigit))), current.end()); 
     date[i] = atoi(current.substr(0,8).c_str()); 
     time[i] = atoi(current.substr(8,12).c_str()); 
    } 

    return List::create(_["date"]=date, _["time"]=time); 
}   

Замерим это:

> dates <- rep("2011-03-23T12:23:32.123", 1e+05) 
> system.time(res1 <- datetimeToInt(dates)) 
    user system elapsed 
    0.081 0.006 0.087 
> system.time(res2 <- datetimeToInt2(dates)) 
    user system elapsed 
    0.044 0.000 0.044 
> identical(res1, res2) 
[1] TRUE  
+0

Спасибо Romain! Я довольно небезопасен с векторами 'CharacterVector', я не понимал, что вы можете применять STL algos к элементам' CharacterVector'. Как правило, кажется, что вы не можете сравнивать элементы 2 'CharacterVector' с оператором' == '... Я немного озадачен этим – statquant

+0

Ну, важно то, что' current = datetimes [i]; 'он получает элемент и присваивает это в 'std :: string'. –

+0

Не оставляйте свои разочарования частным. Если есть что-то, что вы хотели бы увидеть (например, поддержка 'operator ==' сообщите нам о списке рассылки Rcpp. Иногда вещей нет, потому что у нас еще не было необходимости. –

1

Вы можете посмотреть на fasttime пакет Саймоном (доступно here on rforge.net), который делает что-то очень похожее.

Он разделяет строки времени datetime ISO (хотя и с разделителем 'T'), которые считаются UTC раз, используя только строковые операции и отсутствие синтаксического анализа. Я использовал его все время, так как он мне подходит.

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

Наконец, не используйте строку или int для арифметики или сопоставлений даты, когда вы можете использовать правильные типы дат, какие у R, C++ и Rcpp есть.

+0

Привет, Дирк, спасибо за ваши предложения. Все они держатся в целом, но не в моем конкретном случае. Я уже являюсь пользователем «fasttime» и «fastPOSIXct», поэтому я задал этот вопрос, но мое решение было менее эффективным, чем «fastPOSIXct», даже если оно делало меньше. Я использую 'integer' для даты и времени (до милли), потому что я являюсь тяжелым пользователем' data.table', который использует сортировку 'radix' (и больше). Вы получаете много особых проблем, используя 'integer' вместо' double' (мой вариант использования). Конечно, вы правы насчет 'POSIXct' vs' string' или 'integer' на общем основании. – statquant

+0

И я жду вашей книги до контейнеров STL vs Rcpp, поскольку мои знания в области программирования плохи. НО меня очень интересует то, что вы предлагаете здесь! – statquant

+0

Я предлагаю придерживаться типов Rcpp, если вам не требуется что-то конкретное из других типов (stl, ...). Использование типов Rcpp будет использовать собственную память R, и поэтому migth избавит вас от создания слишком большого количества копий. Типичный случай использования типов stl над типами Rcpp - это когда вы увеличиваете/сокращаете структуры данных. Rcpp, ограниченный моделью данных R, здесь не очень полезен. –

Смежные вопросы