Сортировка строк C ++ по нескольким критериям - PullRequest
2 голосов
/ 01 июля 2010

Мне нужно отсортировать C ++ std::vector<std::string> fileNames.Имена файлов помечены так:

YYDDDTTTT_Z_SITE

YY = Год (то есть 2009 = 09, 2010 = 10) DDD = День года (то есть 1 января = 001, 31 декабря = 365)TTTT = время дня (т.е. полночь = 0000, полдень = 1200)

ZONE = будет либо E, либо W

SITE = четырехбуквенное имя сайта (т.е. HILL, SAMM)

Мне нужно отсортировать строки в следующем порядке: ZONE, SITE, YY, DDD, TTTT

Ответы [ 7 ]

7 голосов
/ 01 июля 2010

Используйте std::sort с функцией сравнения.

(хороший пример ссылки)

2 голосов
/ 01 июля 2010

Простая часть: напишите саму сортировку:

// Return true if the first arg is strictly less than the second
bool compareFilenames(const std::string& rhs, const std::string& lhs);
...
std::sort(fileNames.begin(), fileNames.end(), &compareFilenames);

Более сложная часть: написание самого сравнения.В псевдокоде, для полной общности:

bool compareFilenames(const std::string& lhs, const std::string& rhs)
{
    parse the filenames
    if (lhs zone != rhs zone)
        return lhs zone < rhs zone
    if (lhs site != rhs site)
        return lhs site < rhs site
    ...
    return false
}

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

Учитывая строгийТем не менее, у вас есть структура имен файлов и ваши конкретные потребности в сортировке, вы можете просто разделить строку по первому символу '_' и выполнить лексикографическое сравнение второго фрагмента, после первого фрагмента, если второй блок равенравны.Это сделает код для синтаксического анализа имени файла намного проще, что может привести к гибкости в случае изменения формата именования файлов.

1 голос
/ 01 июля 2010

Используйте std::sort и реализуйте класс сравнения

посмотрите в http://www.cplusplus.com/reference/stl/list/sort/ для получения более подробной информации

1 голос
/ 01 июля 2010

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

0 голосов
/ 03 июля 2010

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

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include "boost/lambda/detail/operator_actions.hpp"
#include "boost/lambda/detail/operator_return_type_traits.hpp"
#include "boost/lambda/detail/control_structures_impl.hpp"
#include "boost/ref.hpp"
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <cassert>

using namespace std;
using namespace boost::lambda;

//helpers: a better way would be to group them
//under a flyweight, or something...
string extract_year(string str_)
{
    return str_.substr(0,2);
}

string extract_dayofyear(string str_)
{
    return str_.substr(2,3);
}

string extract_timeofday(string str_)
{
    return str_.substr(5,4);
}

string extract_zone(string str_)
{
    return str_.substr(10,1);
}

string extract_site(string str_)
{
    return str_.substr(12,4);
}

//Uhm, just for brevity... ('cause otherwise we should stay away from macros ;-)
#define IF_THEN_ELSE_RET(op1,op2,exp) if_then_else_return(var(op1)<var(op2),true,if_then_else_return(var(op1)>var(op2),false,exp))

void sort_fnames(vector<string>& fnames)
{
    string z1,z2,s1,s2,y1,y2,d1,d2,t1,t2;

    //sort by zone-then-site-then-year-then-day-then-time:
    //Note the format of the sort(fnames.begin(),fnames.end(), (,...,boolean_expression) );
    //remember, in a sequence of comma-dellimited statements enclosed between parens, like
    //val=(.,...,boolean_expression); only the last expression, boolean_expression, gets
    //assigned to variable "val";
    //So, in the sort() call below, the statements 
    //var(z1)=bind(extract_zone,_1),var(z2)=bind(extract_zone,_2), etc.
    //are only initializing variables that are to be used in the composition 
    //of if_then_else_return(,,) lambda expressions whose composition 
    //combines the zone-then-site-then-year-then-day-then-time criteria 
    //and amounts to a boolean that is used by sort to decide the ordering
    sort(fnames.begin(),fnames.end(),
        (var(z1)=bind(extract_zone,_1),var(z2)=bind(extract_zone,_2),
         var(s1)=bind(extract_site,_1),var(s2)=bind(extract_site,_2),
         var(y1)=bind(extract_year,_1),var(y2)=bind(extract_year,_2),
         var(d1)=bind(extract_dayofyear,_1),var(d2)=bind(extract_dayofyear,_2),
         var(t1)=bind(extract_timeofday,_1),var(t2)=bind(extract_timeofday,_2),
         IF_THEN_ELSE_RET(z1,z2,IF_THEN_ELSE_RET(s1,s2,IF_THEN_ELSE_RET(y1,y2,IF_THEN_ELSE_RET(d1,d2,IF_THEN_ELSE_RET(t1,t2,true)))))
         ));
}
0 голосов
/ 01 июля 2010

Ваш предикат сортировки, который вы передаете vector::sort(), может создавать переупорядоченные временные строки строки, которую он затем сравнивает.

0 голосов
/ 01 июля 2010

Вы можете использовать qsort с вашей собственной функцией сравнения строк, которая учитывает ваши правила сортировки и адрес первого элемента в каждом векторе, где он запрашивает массив.
http://www.cplusplus.com/reference/clibrary/cstdlib/qsort/

Но ты не должен. Просто используйте std::sort

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