Мне нужно иметь возможность сортировать вектор объектов по имени, размеру и другим свойствам, сохраняя их сгруппированными (например, по указанному выше идентификатору группы).
На самом деле, я пытаюсь сделать наоборот. Сначала я хочу отсортировать вектор по вторичному атрибуту (например, имени, размеру и т. Д.), А затем убедиться, что все элементы вектора содержатся в группах.
Результат должен быть одинаковым независимо от того, как вы о нем думаете, если только вы не хотите использовать вектор в промежуточном состоянии, где он не отсортирован по идентификатору группы. Если это не так, я не могу понять, почему нельзя использовать функцию сравнения, использующую два критерия (где идентификатор группы является основным условием, а имя / размер / другое является вторичным). Вы даже можете создать общий объект сравнения, который сочетает в себе использование двух предикатов (by_two_criteria):
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <cstdlib>
template <class FirstCondition, class SecondCondition>
class by_two_criteria_t
{
FirstCondition first;
SecondCondition second;
public:
by_two_criteria_t(FirstCondition f, SecondCondition s): first(f), second(s) {}
template <class T>
bool operator()(const T& a, const T& b) const
{
return first(a, b) || (!first(b, a) && second(a, b));
}
};
template <class FirstCondition, class SecondCondition>
by_two_criteria_t<FirstCondition, SecondCondition> by_two_criteria(FirstCondition f, SecondCondition s)
{
return by_two_criteria_t<FirstCondition, SecondCondition>(f, s);
}
class X
{
int group;
int value;
public:
X(int g, int n): group(g), value(n) {}
friend bool compare_group(const X& a, const X& b);
friend bool compare_value(const X& a, const X& b);
friend std::ostream& operator<<(std::ostream& os, const X& x) { return os << x.group << ", " << x.value; }
};
bool compare_group(const X& a, const X& b) { return a.group < b.group; }
bool compare_value(const X& a, const X& b) { return a.value < b.value; }
X random_x()
{
return X(rand() % 10, rand() % 20);
}
int main()
{
using namespace std;
vector<X> vec;
generate_n(back_inserter(vec), 100, random_x);
sort(vec.begin(), vec.end(), by_two_criteria(compare_group, compare_value));
copy(vec.begin(), vec.end(), ostream_iterator<X>(cout, "\n"));
}
И просто для удовольствия, вот функтор, который объединяет n критерий сравнения (C ++ 0x только для шаблонов с переменными числами и синтаксиса инициализации нового стиля):
#include <functional>
template <class T, class ...Fun>
class n_criteria_t {};
template <class T, class Fun1, class ...FunN>
class n_criteria_t<T, Fun1, FunN...>: public std::binary_function<T, T, bool>
{
public:
n_criteria_t(Fun1 f1, FunN... fn): f1(f1), f2(fn...) {}
bool operator() (const T& a, const T& b) const
{
return f1(a, b) || (!f1(b, a) && f2(a, b));
}
private:
Fun1 f1;
n_criteria_t<T, FunN...> f2;
};
template <class T, class Fun1>
class n_criteria_t<T, Fun1>: public std::binary_function<T, T, bool>
{
public:
n_criteria_t(Fun1 f1): f1(f1) {}
bool operator() (const T& a, const T& b) const
{
return f1(a, b);
}
private:
Fun1 f1;
};
template <class T, class ...Fun>
n_criteria_t<T, Fun...> n_criteria(Fun... f)
{
return {f...};
}