Можно ли сохранить элемент структуры как переменную? - PullRequest
2 голосов
/ 22 октября 2019

У меня есть оператор switch, который на основе ввода пользователя будет сортировать массив на основе массива [i] .name или сортировать по массиву [i] .mark

    switch(input){
        case 1:
            for(int i = 1; i < size; i++){
                structure_name choice = Array[i];
                int j = i - 1;
                while(j >= 0 && tolower(choice.name[0]) <= tolower(Array[j].name[0])){
                    Array[j + 1] = Array[j];
                    j = j - 1;
                }
                Array[j+1] = choice;
            }
            break;
        case 2:
            for(int i = 1; i < size; i++){
                structure_name choice = Array[i];
                int j = i - 1;
                while(j >= 0 && choice.mark <= Array[j].mark){
                    Array[j + 1] = Array[j];
                    j = j - 1;
                }
                Array[j+1] = choice;
            }
            break;
        default:
            break;
    }

Как видите, явыполняю сортировку выбора дважды. Можно ли выполнить что-то вроде ...

    if(input == 1){
        option = .name
    }else if(input == 2){
        option = .mark
    }

, чтобы я мог использовать только одну сортировку и изменить, какую переменную он берет из массива. Примечание: я не могу использовать sort (), я должен использовать алгоритм сортировки, который я написал. Отсюда дилемма в том, что я стараюсь избегать написания одного и того же кода дважды.

Ответы [ 4 ]

3 голосов
/ 22 октября 2019

Я думаю, вы можете использовать различные функции компаратора в качестве «опций». И дайте желаемый компаратор функции сортировки, используете ли вы std::sort или пользовательскую ручную функцию.

Учитывая следующее struct (которое вы забыли указать):

struct MyStruct
{
    std::string name;
    int mark;
};

Вы можете определить свои «опции» как функции компаратора:

int mark_cmp(const MyStruct & lhs, const MyStruct & rhs)
{
    return lhs.mark < rhs.mark; // Compare by mark
}
int name_cmp(const MyStruct & lhs, const MyStruct & rhs)
{
    return lhs.name.compare(rhs.name); // Compare by name
}

Тогда вы можете просто написать:

int main()
{
    unsigned int input = 1;

    MyStruct arr[5] {{"foo", 5}, {"bar", 6}, {"baz", -9}, {"foobar", 0}, {"foobaz", -3}};

    switch(input)
    {
        case 1: std::sort(arr, arr+5, &name_cmp); // input == 1 ? sort by name
            break;
        case 2: std::sort(arr, arr+5, &mark_cmp); // input == 2 ? sort by mark
            break;
        default:;
    }

    return 0;
}

Примечание: Вам не нужноbreak после последнего оператора в switch (в вашем случае после default нет необходимости break).

Примечание2: Я использовал необработанный массивбыть ближе к тому, что вы сделали, но я бы посоветовал вам использовать std::array вместо этого. Или std::vector, если вам нужен динамический контейнер.


Если вы не можете использовать std::sort, вы можете создать свою собственную функцию сортировки, которая принимает функцию компаратора в качестве параметров, и она будет работать тоже.

2 голосов
/ 22 октября 2019

Это просто, если эти поля имеют одинаковый тип. Обратите внимание, что в C ++ правильный термин является переменной-членом, а не полем. Вы можете использовать указатель на член.

struct structure_name {
    std::string name;
    std::string mark;
};

int main()
{
    structure_name S  = { "name", "test"};

    // p now points at name field
    // p can point at any std::string in structure_name 
    std::string structure_name::* p  = &structure_name::name;

    // p is dereferenced using  object S.
    std::cout << (S.*p) << std::endl;
}

В вашем случае option должен быть таким указателем

Если поля имеют разные типы, следует использовать метод стирания некоторого типа. Существует два оператора разыменования, .* и ->*.

, если параметр сортировки известен статически, вы можете создать шаблон алгоритма сортировки, используя тип поля в качестве параметра шаблона. Так что вы будете писать его один раз, но дважды для каждого поля.

1 голос
/ 22 октября 2019

Вместо дублирования алгоритма сортировки, вы можете использовать его только один раз и поместить входное сравнение в алгоритм сортировки. Что-то похожее на то, что вы пытаетесь сделать, это определить правильный компаратор и передать его в общую функцию сортировки. Если нет никаких требований, которые вы не упомянули, я бы просто использовал для этого std::sort:

#include <iostream>
#include <array>
class foo {
public:
    int mark;
    std::string name;
};
int main() {
    std::array<foo, 100> Array;
    // initialize Array here
    int input;
    std::cin >> input;
    if (input == 1) {
        std::sort(Array.begin(), Array.end(), [](foo& a, foo& b) {
            return a.mark > b.mark;
        });
    }
    else if (input == 2) {
        std::sort(Array.begin(), Array.end(), std::less<int>());
    }
    else
        std::cout << "Invalid input of " << input << ", did not sort." << std::endl;
}
0 голосов
/ 22 октября 2019

Я думаю, вы могли бы сделать что-то вроде этого:

auto f1 = [](fix_type name1, fix_type name2) {
 return tolower(choice.name[0]) <= tolower(Array[j].name[0]);
}

auto f2 = [](fix_type name1, fix_type name2) {
 return choice.mark <= Array[j].mark;
}

std::function<bool(fix_type, fix_type)> f;

if(input == 1){
  f = f1;
}else if(input == 2){
  f = f2;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...