сортировка std::set c++

159
24 июня 2019, 10:40

у меня есть std::set с кастомным компаратором, в set я кладу свой тип данных, который содержит два параметра, уникальность должна обеспечиваться по первому параметру, а сортировка должна производиться по второму параметру

std::set<MyType, MyCastomLess> _set;
auto tmp_1 = MyType( 1, 9);
auto tmp_2 = MyType( 2, 8);
auto tmp_3 = MyType( 3, 7);
auto tmp_4 = MyType( 1, 6);
auto tmp_5 = MyType( 1, 5);
auto tmp_6 = MyType( 3, 4);
auto tmp_7 = MyType( 2, 3);
_set.insert(tmp_1 );
_set.insert(tmp_2 );
_set.insert(tmp_3 );
_set.insert(tmp_4 );
_set.insert(tmp_5 );
_set.insert(tmp_6 );
_set.insert(tmp_7 );

для получения первого параметра у меня есть функция get_first(), для второго get_second(). Вот сама функция less():

struct MyCastomLess{
bool operator()(MyType const &lhs,MyType const & rhs) const 
{
    return  (lhs->get_first() < rhs->get_first()) && (lhs->get_second() != rhs->get_second());
}
};

у меня никак не сортируется по второму параметру, а если я напишу вот так:

return  !(lhs->get_first() == rhs->get_first()) && (lhs->get_second() < rhs->get_second());

то в set будет отсортирован по второму параметру, но в него будут попадать переменные с одинаковым первым параметром, а это неправильно, должна быть уникальность.

я ожидаю, что на выходе, в моем set будут находиться элементы tmp_1 , tmp_2 , tmp_3, потому что после них у остальных элементов первый параметр уже не уникальный, а располагаться они там будут в таком порядке: tmp_3, tmp_2, tmp_1, так как сортироваться они должны по второму параметру, и все это в рамках одной структуры MyCastomLess.

как мне это сделать?

Answer 1

Если вам нужна "уникальность по первому параметру", это автоматически означает, что и сортировать ваш std::set вам придется именно по первому параметру. В std::set невозможно "оторвать" уникальность от сортировки. Не существует способа в одном std::set обеспечить "уникальность по первому параметру", если сортировка выполняется по второму.

Если вам упорядочение по второму нужно только "потом", то просто собираем std::set (или std::unordered_set) c уникальным первым. Затем перебрасываем все в вектор и сортируем там по второму.

Если вам упорядочение по второму нужно "на лету", то придется строить более сложную структуру данных, т.е. к основной структуре, использующей первое поле в качестве ключа (std::set или std::unordered_set), еще добавлять дополнительный индекс по второму полю (std::multiset<MyType *> или std::multiset<итератор первого контейнера>).

Например

#include <set>
#include <unordered_set>
#include <iostream>
struct MyType
{
  unsigned first, second;
};
struct MyTypeHasherFirst
{
  size_t operator ()(const MyType &v) const
    { return std::hash<unsigned>()(v.first); }
  bool operator ()(const MyType &lhs, const MyType &rhs) const
    { return lhs.first == rhs.first; }
};
using FirstSet = std::unordered_set<MyType, MyTypeHasherFirst, MyTypeHasherFirst>;
struct MyTypeComparatorSecond
{
  bool operator ()(const FirstSet::const_iterator lhs, 
                   const FirstSet::const_iterator rhs) const
    { return lhs->second < rhs->second; }
};
using SecondSet = std::multiset<FirstSet::const_iterator, MyTypeComparatorSecond>;
int main()
{
  FirstSet first;
  SecondSet second;
  // Вставка
  MyType arr[] = 
  { 
    { 1, 9 }, { 2, 8 }, { 3, 7 }, { 1, 6 }, { 1, 5 }, { 3, 4 }, { 2, 3 } 
  };
  for (const MyType &v : arr)
    if (auto r = first.insert(v); r.second)
      second.insert(r.first);
  // Результат
  for (FirstSet::const_iterator it : second)
    std::cout << "{ " << it->first << ", " << it->second << " }" << std::endl;
  std::cout << std::endl;
  // Вставка еще
  MyType arr2[] = 
  { 
    { 2, 5 }, { 4, 1 }, { 8, 3 }, { 1, 6 }, { 4, 4 }, { 6, 7 }, { 2, 9 } 
  };
  for (const MyType &v : arr2)
    if (auto r = first.insert(v); r.second)
      second.insert(r.first);
  // Результат
  for (FirstSet::const_iterator it : second)
    std::cout << "{ " << it->first << ", " << it->second << " }" << std::endl;
  std::cout << std::endl;
}
READ ALSO
Элемент Point (org.springframework.data.geo.Point) сохраняется в Postgresql как Bytea. Почему и как мне сохранить координаты точки?

Элемент Point (org.springframework.data.geo.Point) сохраняется в Postgresql как Bytea. Почему и как мне сохранить координаты точки?

Начал изучать Java и Spring frameworkДелаю задание, часть которого - хранение набора точек с привязкой к какой-то площади (не важно к какой, к вопросу...

210
SQL запросы в Hibernate

SQL запросы в Hibernate

Могу ли я в контексте Spring + Hibernate сделать простой sql запрос и получить список элементов ( как в JDBC - ResultSet) для запроса данных из таблицы, не входящей...

217
Java Tomcat Listener повторная отправка запроса

Java Tomcat Listener повторная отправка запроса

Написал в томкате в webxml

142