Risolvendo questa assegnando ID ai campi presenta diversi inconvenienti:
- casi non possono essere coperti (come indicato dalla
throw
)
- ordinamento inverso richiede una bandiera in più
- Non è evidente dal codice che ID sta per quale campo
- Non è facilmente estendibile (è sempre necessario aggiornare le mappature ID)
In alternativa, è possibile definire "comparatori", che restituiscono -1
, 0
o 1
, a seconda che il primo argomento sia inferiore, uguale o maggiore del secondo, rispettivamente. Questi comparatori possono quindi essere combinati e invertiti in modo abbastanza generico e utilizzati come predicati di ordinamento.
Dato un insieme di questi comparatori per i campi della vostra struct, si può comporre di loro in questo modo:
Comparator byYearReverseAndMonth = compose(reverse(byYear), byMonth);
std::sort(values.begin(), values.end(), with(byYearReverseAndMonth));
Modifica in risposta al commento:
Naturalmente non è necessario per definire ciascuna combinazione di comparatori e comparatori inversi al momento della compilazione. Invece, è possibile raccogliere i comparatori desiderati per il prossimo ordinamento in fase di esecuzione, ad esempio, in un vector<Comparator>
. Gli esempi di confronto potrebbero, per esempio, essere associate le colonne di una tabella:
vector<Comparator> comparators;
for (each selected column) {
comparators.push_pack(comparatorFor(column));
}
Questi comparatori possono essere costituiti in un unico, con un semplice ciclo su tutti i comparatori:
Comparator composedComparator = comparators[0];
for (int i=1; i<comparators.size(); ++i) {
composedComparator = compose(comparator, comparators[i]);
}
sort(v.begin(),v.end(),with(composedComparator));
un abbozzo di ciò che questo può apparire come:
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
struct MyStruct
{
int id;
std::string currencyCode;
int month;
int year;
int amount;
};
typedef std::function<int(const MyStruct& s0, const MyStruct& s1)> Comparator;
typedef std::function<bool(const MyStruct& s0, const MyStruct& s1)> Predicate;
template <typename T>
std::function<int(const T&, const T&)> compose(
std::function<int(const T&, const T&)> c0,
std::function<int(const T&, const T&)> c1)
{
return[c0, c1](const T& t0, const T& t1) -> int
{
int r0 = c0(t0, t1);
if (r0 != 0)
{
return r0;
}
return c1(t0, t1);
};
}
template <typename T>
std::function<int(const T&, const T&)> reverse(
std::function<int(const T&, const T&)> c)
{
return[c](const T& t0, const T& t1) -> int
{
return -c(t0, t1);
};
}
template <typename T>
std::function<bool(const T&, const T&)> with(
std::function<int(const T&, const T&)> comparator)
{
return[comparator](const T& t0, const T& t1)
{
return comparator(t0, t1) < 0;
};
}
void print(std::vector<MyStruct>& values)
{
for (auto it = values.begin(); it != values.end(); ++it)
{
std::cout << (*it).month << "-"
<< (*it).year << " id "
<< (*it).id << std::endl;
}
}
int main(int argc, char** argv)
{
std::vector<MyStruct> values;
MyStruct m;
m.year = 1981; m.month = 1; m.id = 4; values.push_back(m);
m.year = 1980; m.month = 2; m.id = 5; values.push_back(m);
m.year = 1980; m.month = 4; m.id = 2; values.push_back(m);
m.year = 1980; m.month = 3; m.id = 3; values.push_back(m);
m.year = 1980; m.month = 4; m.id = 1; values.push_back(m);
std::cout << "Before sorting" << std::endl;
print(values);
Comparator byMonth = [](const MyStruct& s0, const MyStruct& s1)
{
if (s0.month < s1.month) return -1;
if (s0.month > s1.month) return 1;
return 0;
};
Comparator byYear = [](const MyStruct& s0, const MyStruct& s1)
{
if (s0.year < s1.year) return -1;
if (s0.year > s1.year) return 1;
return 0;
};
Comparator byId = [](const MyStruct& s0, const MyStruct& s1)
{
if (s0.id < s1.id) return -1;
if (s0.id > s1.id) return 1;
return 0;
};
Comparator byYearAndMonth = compose(byYear, byMonth);
std::sort(values.begin(), values.end(), with(byYearAndMonth));
std::cout << "After sorting by year and month:" << std::endl;
print(values);
Comparator byYearReverseAndMonth = compose(reverse(byYear), byMonth);
std::sort(values.begin(), values.end(), with(byYearReverseAndMonth));
std::cout << "After sorting by year reverse and month:" << std::endl;
print(values);
Comparator byYearAndMonthAndId = compose(byYearAndMonth, byId);
std::sort(values.begin(), values.end(), with(byYearAndMonthAndId));
std::cout << "After sorting by year and month and id:" << std::endl;
print(values);
return 0;
}
(Ci scusiamo per i potenziali gaffe, io sono un C++ newb ie)
[Boost.MultiIndex] (http://www.boost.org/doc/libs/1_58_0/libs/multi_index/doc/index.html) è stato realizzato per questo scopo. [questo esempio] (http://www.boost.org/doc/libs/1_58_0/libs/multi_index/example/basic.cpp) è quasi letteralmente il tuo caso. – rwols
@nwols: la memorizzazione e il mantenimento costante degli indici per tutti gli ordinamenti supportati (più di 20 ha senso) non mi sembra un buon approccio ... –