“Псевдоним” для полей структуры в векторе для сортировки последнего

117
18 декабря 2020, 03:00

Есть структура:

struct data
{
    int         id;
    std::string surname;
    std::string name;
    std::string patronymic;
    std::string post;
    double      hrPay;
    int         hours;
};

Есть вектор этих структур:

std::vector<data> m_personal;

Также, имеем функцию выбора метода сортировки вектора и поля сортировки:

char m_sort_choice;
void sortData()
{
    std::string myChoice;
    char m_sort_choice;
    do
    {
        std::cout << "Sort by:\n";
        std::cout << "    - ID.         Press 1 \n" <<
                     "    - Surname.    Press 2 \n" <<
                     "    - Name.       Press 3 \n" <<
                     "    - Patronymic. Press 4 \n" <<
                     "    - Post.       Press 5 \n" <<
                     "    - Hr. pay.    Press 6 \n" <<
                     "    - Hours.      Press 7 \n" <<
                     "    - Salary.     Press 8 \n" <<
                     "    - Press q to Quit     \n"  ;
        std::cin >> m_sort_choice;
        switch (m_sort_choice)
        {
            case '1': myChoice = "ID";         break;
            case '2': myChoice = "Surname";    break;
            case '3': myChoice = "Name";       break;
            case '4': myChoice = "Patronymic"; break;
            case '5': myChoice = "Post";       break;
            case '6': myChoice = "Hr. pay";    break;
            case '7': myChoice = "Hours";      break;
            case '8': myChoice = "Salary";     break;
            case 'q': return;
            case 'Q': return;
            default: m_sort_choice = 'w';      break;
        }
    } while (m_sort_choice == 'w');
    char method;
    do
    {
        std::cout << "Choose method by sort:  \n"  <<
                     "    - Press 1 to Quick  \n"  <<
                     "    - Press 2 to Shell  \n"  <<
                     "    - Press 3 to Bubble \n"  <<
                     "    - Press Q to quit   \n"   ;
        std::cin >> method;
        switch (method)
        {
            case '1': std::cout << "Sort by " << myChoice <<
                                   ", Method: Quick. \n";
                                   std::sort (m_personal.begin(), m_personal.end(), comp);;
                                   break;
            case '2': std::cout << "Sort by " << myChoice <<
                                   ", Method: Shell. \n";
                                   sortShell();
                                   break;
            case '3': std::cout << "Sort by " << myChoice <<
                                   ", Method: Bubble. \n";
                                   sortBubble();
                                   break;
            case 'q': return;
            case 'Q': return;
            default: method = 'w'; break;
        }
        showAll();
    } while (method == 'w');
}

И саму функцию сортировки, которая выглядит так:

void sortBubble()
{
    std::vector<data> &arr = m_personal;
    for (unsigned int iii = 0; iii < arr.size() - 1; iii++) {
        for (unsigned int jjj = 0; jjj < arr.size() - iii - 1; jjj++) {
            switch (m_sort_choice)
            {
                case '1': if (arr.at(jjj).id > arr.at(jjj+1).id)
                                   {  std::swap(arr.at(jjj), arr.at(jjj+1)); };
                          continue;
                          break;
                case '2': if (arr.at(jjj).surname > arr.at(jjj+1).surname)
                                   {  std::swap(arr.at(jjj), arr.at(jjj+1)); };
                          continue;
                          break;
                case '3': if (arr.at(jjj).name > arr.at(jjj+1).name)
                                   {  std::swap(arr.at(jjj), arr.at(jjj+1)); };
                          continue;
                          break;
                case '4': if (arr.at(jjj).patronymic > arr.at(jjj+1).patronymic)
                                   {  std::swap(arr.at(jjj), arr.at(jjj+1)); };
                          continue;
                          break;
                case '5': if (arr.at(jjj).post > arr.at(jjj+1).post)
                                   {  std::swap(arr.at(jjj), arr.at(jjj+1)); };
                          continue;
                          break;
                case '6': if (arr.at(jjj).hrPay > arr.at(jjj+1).hrPay)
                                   {  std::swap(arr.at(jjj), arr.at(jjj+1)); };
                          continue;
                          break;
                case '7': if (arr.at(jjj).hours > arr.at(jjj+1).hours)
                                   {  std::swap(arr.at(jjj), arr.at(jjj+1)); };
                          continue;
                          break;
                case '8': if (arr.at(jjj).hours * arr.at(jjj).hrPay >
                              arr.at(jjj+1).hours * arr.at(jjj+1).hours)
                                   {  std::swap(arr.at(jjj), arr.at(jjj+1)); };
                          continue;
                          break;
                default:  break;
            }
        }
    }
}

А хотелось бы её привести примерно к такому виду:

void sortBubble()
{
    std::vector<data> &arr = m_personal;
    auto x;
    switch (m_sort_choice)
    {
        case '1': x = arr.id;         break;
        case '2': x = arr.surname;    break;
        case '3': x = arr.name;       break;
        case '4': x = arr.patronymic; break;
        case '5': x = arr.post;       break;
        case '6': x = arr.hrPay;      break;
        case '7': x = arr.hours;      break;
        case '8': x = arr.hours * arr.hrPay; break;
        default:  break;
    }
    for (unsigned int iii = 0; iii < arr.size() - 1; iii++) {
        for (unsigned int jjj = 0; jjj < arr.size() - iii - 1; jjj++) {
             if (arr.at(jjj).x > arr.at(jjj+1).x)
                          std::swap(arr.at(jjj), arr.at(jjj+1)); 
        }
    }
}

Или:

void sortBubble( std::string myChoice )
    {
        std::vector<data> &arr = m_personal;       
        for (unsigned int iii = 0; iii < arr.size() - 1; iii++) {
            for (unsigned int jjj = 0; jjj < arr.size() - iii - 1; jjj++) {
                 if (arr.at(jjj).myChoice > arr.at(jjj+1).myChoice)
                              std::swap(arr.at(jjj), arr.at(jjj+1)); 
            }
        }
    }

Есть ли какой-нибудь способ реализовать подобное?

Answer 1

Для этого можно вынести предикат сравнения из функции сортировки:

using Predicate = bool (data const & left, data const & right);
void sortBubble(::std::vector<data> & items, Predicate & predicate)
{
    if(::std::size_t{1} < items.size())
    {
        for(::std::size_t iii{}; iii < items.size() - 1; ++iii)
        {
            for(::std::size_t jjj{}; jjj < items.size() - iii - 1; ++jjj)
            {
                if(predicate(items.at(jjj), items.at(jjj + 1)))
                {
                    ::std::swap(items.at(jjj), items.at(jjj + 1)); 
                }
            }
        }
    }
}
Predicate * p_predicate{};
switch (m_sort_choice)
{
    case '1': p_predicate = [](data const & left, data const & right){ return left.id      > right.id     ;}; break;
    case '2': p_predicate = [](data const & left, data const & right){ return left.surname > right.surname;}; break;
    case '3': p_predicate = [](data const & left, data const & right){ return left.name    > right.name   ;}; break;
    ...
    default:  p_predicate = nullptr; break;
}
if(p_predicate)
{
    sortBubble(items, *p_predicate);
}

Кроме того, для простых предикатов, сравнивающих по определенному полю, можно написать шаблон использовать его вместо лямбда-выражений:

template<auto x_p_field> bool
gt_field(data const & left, data const & right)
{
    return (left.*x_p_field) > (right.*x_p_field);
}
case '1': p_predicate = &gt_field<&data::id>; break;
case '2': p_predicate = &gt_field<&data::surname>; break;
Answer 2

Итак, если кому интересно, благодаря пользователю VIT пришёл к следующему решению:

bool comp (const data &a, const data &b)
{
    switch (m_sort_choice)
    {
        case '1': return a.id         < b.id;
        case '2': return a.surname    < b.surname;
        case '3': return a.name       < b.name;
        case '4': return a.patronymic < b.patronymic;
        case '5': return a.post       < b.post;
        case '6': return a.hrPay      < b.hrPay;
        case '7': return a.hours      < b.hours;
        case '8': return a.hours * a.hrPay < b.hours * b.hrPay;
        default:  break;
    }
    return 0;
}
void sortBubble()
{
    std::vector<data> &arr = m_personal;
    for (unsigned int iii = 0; iii < arr.size() - 1; iii++) {
        for (unsigned int jjj = 0; jjj < arr.size() - iii - 1; jjj++) {
            if (comp(arr.at(jjj+1), arr.at(jjj)))
                std::swap(arr.at(jjj), arr.at(jjj+1));
        }
    }
}

Функция comp() у меня используется как компаратор для функции быстрой сортировки, поэтому "странный" порядок аргументов при её вызове.

READ ALSO
unsigned char* и char* при работе со строками

unsigned char* и char* при работе со строками

Могут ли возникнуть проблемы с работой со строками если использовать не char* /const char*, а unsigned char*/const unsigned char*? Если все правильно, к примеру, в UTF-8,...

118
500 (Internal Server Error)

500 (Internal Server Error)

Имеется форма с двумя выпадающими списками и одной кнопкойПо нажатию на кнопку отправляются данные в виде json, на основе этих данных выполняется...

149
encodeURIComponent синтаксис

encodeURIComponent синтаксис

Как правильно кусок кода засунуть в encodeURIComponent при отправке ajax запроса?

129