Rozwiązanie to poprzez przypisanie identyfikatorów pól ma kilka wad:
- przypadkach może być pokryty (na co wskazuje
throw
)
- Sortowanie w kolejności odwrotnej wymaga dodatkowego flagę
- To nie jest oczywiste z kodu, który stoi ID, dla których pole
- Nie jest łatwo rozszerzalny (zawsze trzeba zaktualizować mapowania ID)
Alternatywnie można zdefiniować "komparatory", które zwracają wartość, w zależności od tego, czy pierwszy argument jest mniejszy, równy lub większy niż drugi. Komparatory te można następnie łączyć i odwracać dość ogólnie i używać jako predykatu sortowania.
Biorąc pod uwagę zestaw tych komparatorów dla dziedzin swojej struktury, można komponować je tak:
Comparator byYearReverseAndMonth = compose(reverse(byYear), byMonth);
std::sort(values.begin(), values.end(), with(byYearReverseAndMonth));
Edycja w odpowiedzi na komentarz:
Oczywiście to nie niezbędne do zdefiniowania każdej kombinacji komparatorów i komparatorów wstecznych w czasie kompilacji. Zamiast tego można zbierać pożądane komparatory dla następnego sortowania w czasie wykonywania, na przykład w vector<Comparator>
. Te przykłady porównawcze może na przykład być związany z kolumny tabeli:
vector<Comparator> comparators;
for (each selected column) {
comparators.push_pack(comparatorFor(column));
}
te komparatory można następnie składa się w jedną z prostą pętli na wszystkich komparatorów:
Comparator composedComparator = comparators[0];
for (int i=1; i<comparators.size(); ++i) {
composedComparator = compose(comparator, comparators[i]);
}
sort(v.begin(),v.end(),with(composedComparator));
szkic co to może wyglądać następująco:
#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;
}
(przeprosiny za potencjalnych faux pas, jestem newb C++ tj)
[Boost.MultiIndex] (http://www.boost.org/doc/libs/1_58_0/libs/multi_index/doc/index.html) został stworzony w tym celu. [ten przykład] (http://www.boost.org/doc/libs/1_58_0/libs/multi_index/example/basic.cpp) jest niemal dosłownie twoją sprawą. – rwols
@nwols: ciągłe przechowywanie i utrzymywanie indeksów dla wszystkich obsługiwanych zamówień sortowania (ponad 20 ma sens) nie wydaje mi się szczególnie dobrym podejściem ... –