Блог пользователя BekzhanKassenov

Автор BekzhanKassenov, история, 8 лет назад, По-русски

Привет, сообщество и с наступающим Новым Годом!

Решая одну задачу, придумал интересный макрос, позволяющий сортировать объекты по определенному полю. Получается очень лаконично, но требует C++11. Собственно, макрос:

#define by(T, x) [](const T& a, const T& b) { return a.x < b.x; }

Использование:

struct Item {
    int a, b;
};

sort(arr, arr + N, by(Item, a));

Полный пример: http://pastebin.com/Cp5ZkwE4.

Всем счастливого нового года!

UPD: В комментариях указали, что C++14 позволяет еще короче:

#define by(x) [](const auto& a, const auto& b) { return a.x < b.x; }
sort(arr, arr + N, by(a));
  • Проголосовать: нравится
  • +122
  • Проголосовать: не нравится

»
8 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Автокомментарий: текст был обновлен пользователем BekzhanKassenov (предыдущая версия, новая версия, сравнить).

  • »
    »
    8 лет назад, # ^ |
      Проголосовать: нравится +16 Проголосовать: не нравится

    В С++14 можно обойтись обойтись только названием поля, потому что там в лямбдах можно писать auto вместо типа.

    • »
      »
      »
      8 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Спасибо, не знал.

      Изначально я так и попытался, но не скомпилировалось в C++11.

      Существуют ли OJ, поддерживающие C++14?

      • »
        »
        »
        »
        8 лет назад, # ^ |
        Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

        Если я не путаю, CodeChef

      • »
        »
        »
        »
        8 лет назад, # ^ |
        Rev. 2   Проголосовать: нравится +18 Проголосовать: не нравится

        Я бы, на всякий случай, написал [](const auto &a, const auto &b), чтобы не искать в стандарте, как же именно передается в лямбду обычный auto — по значению (может долго работать из-за копирования больших структур), или же, по ссылке.

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

    • »
      »
      »
      8 лет назад, # ^ |
        Проголосовать: нравится +44 Проголосовать: не нравится

      MikeMirzayanov, давайте изменим 1 символ в строчке компиляции

»
8 лет назад, # |
  Проголосовать: нравится +24 Проголосовать: не нравится

It is very useful! Thank you :)

»
8 лет назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится

Добавьте пример set с сортировкой по полю, если он есть. В Java это есть, например TreeSet set = new TreeSet((a, b) -> { return a.x.compareTo(b.x); });

  • »
    »
    8 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Я не нагуглил ничего лучше, чем:

    auto temp = by(Item, a);
    set <Item, decltype(temp)> byA(temp);
    

    Минусы: теряется лаконичность, тяжелее запомнить. Проще использовать функтор.

»
8 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Автокомментарий: текст был обновлен пользователем BekzhanKassenov (предыдущая версия, новая версия, сравнить).

»
8 лет назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится

Auto comment: topic has been updated by BekzhanKassenov (previous revision, new revision, compare).

»
8 лет назад, # |
Rev. 2   Проголосовать: нравится +10 Проголосовать: не нравится

UPD: не заметил что топик есть и на английском, заменил этот комментарий на комментарий на английском (см ниже).

»
8 лет назад, # |
  Проголосовать: нравится +1 Проголосовать: не нравится

Just for the fun, it is possible to do the same in c++03 without using any macro. It is not as short macro version, but at least you can't break it by passing something like x || 3 to it.

template<class T, class R, R T::* x> struct by {
    bool operator()(const T& a, const T& b) { return a.*x < b.*x; }
};

sort(arr, arr + N, by<Item, int, &Item::a>());
»
8 лет назад, # |
  Проголосовать: нравится +27 Проголосовать: не нравится

One can go even further and do smth like this:

#define by(T, ...) [](const decltype(T)& a, const decltype(T)& b) { return a.__VA_ARGS__ < b.__VA_ARGS__; }

(decltype is to avoid manual typing of the type name)

Then one can write:

vector<pair<pair<SuperCoolStruct, int>, AnotherCoolStruct>> arr;
sort(arr.begin(), arr.end(), by(arr[0], first.first.someImportantField));