Как суммировать значения встречающихся символов из строки, составлять из них пары и сортировать их в порядке возрастания?

#c #algorithm #sorting #vector #std-pair

#c #алгоритм #сортировка #вектор #std-pair

Вопрос:

Моя задача — написать функцию, которая получает вектор строк в качестве аргумента и возвращает вектор pair<char,int> , содержащий пары, представляющие символы и их частоту (сколько раз появлялась буква), суммированную из всех строк, переданных в vector в качестве аргумента функции. Он также должен быть отсортирован в порядке возрастания.

Приведенный ниже код — это мой подход к тому, как это сделать. Пока я могу только подсчитать, сколько раз символ встречается в каждой строке, но я не могу суммировать все встречающиеся буквы, чтобы получить одну пару.

 #include <iostream>
#include <vector>
#include <utility>
#include <string>

using namespace std;

bool isEqual(const pair<char, int> amp;element) {
    return element.first;
}

vector<pair<char, int>> all_occurrences(vector<string> vec) {

    vector<pair<char, int>> sorted_vec;
    vector<pair<char, int>> final_vec;

    char c;
    int count_chars = 0;
    string element;
    vector<char> check_chars = {' '};
    bool char_found = false;

    for (int i = 0; i < vec.size(); i  ) {

        element = vec[i];

        for (int j = 0; j < element.length(); j  ) {

            c = element.at(j);

            for (int k = 0; k < check_chars.size();   k) {
                if (c == check_chars[k]) {
                    char_found = true;
                    break;
                }
            }

            if (!char_found) {
                check_chars.push_back(c);
                count_chars = count(element.begin(), element.end(), c);
                sorted_vec.push_back(make_pair(c, count_chars));
            }

            char_found = false;

        }
        check_chars = {' '};
    }

    vector<pair<char, int>>::iterator it;

    for (int i = 0; i < sorted_vec.size();   i) {

        it = find_if(sorted_vec.begin(), sorted_vec.end(), isEqual);
        cout << it << endl;

    }


    return sorted_vec;
}

void print_vector(vector<pair<char, int>> pair_vector) {

    cout << "---" << endl;

    for (int i = 0; i < pair_vector.size(); i  ) {
        cout << pair_vector[i].first << ',' << pair_vector[i].second << endl;
    }

    cout << "---" << endl;

}


int main() {

    vector<string> string_vector = {"ala", "ma", "kota"};
    print_vector(all_occurrences(string_vector));
    return 0;
}
 

Комментарии:

1. К вашему сведению, решение (код для all_occurences ) составляет около 5 или 6 строк, если вы готовы использовать std::unordered_map , и пару функций алгоритма STL.

2. я, вероятно, немного растерялся из-за этого, потому что прошло буквально две недели. — И вы получили ответ в течение 10 минут. Не расстраивайтесь этим, поскольку мы ожидаем, что вы узнаете из данного ответа, а не просто скопируете его и передадите своему учителю.

3. @PaulMcKenzie Спасибо за разъяснение, я знаю, что здесь я могу попросить ответы на задачи, которые я еще не понимаю, — и я не ожидаю, что кто-нибудь позволит мне скопировать и вставить код без моего понимания. Гораздо приятнее, когда вы получаете ответ самостоятельно, но иногда его невозможно отменить, когда вы только начинаете. В любом случае, я проанализирую это подробнее и немного почитаю об этом, чтобы получить больше знаний об этом решении, которое кажется мне очень чистым.

Ответ №1:

Сначала вы можете вычислить все значения частоты с помощью std::map :

 std::map<char,int> m;
for(auto c : vec | std::views::join)  // for every char in all strings
    m[c]  ;
 

Затем вы можете скопировать это map в a vector по мере необходимости:

 vector<pair<char, int>> res;
std::ranges::copy(m, std::back_inserter(res));        
 

И, наконец, вы можете отсортировать вектор в порядке возрастания количества частот:

 std::ranges::sort(res, std::less{}, amp;std::pair<char, int>::second);
 

Вот демонстрация.


До C 20 вы можете написать приведенный выше код следующим образом:

Создайте счетчик частоты:

 std::map<char,int> m;
for (auto const amp;s : vec)  // for every string
    for(auto c : s)        // for every character
        m[c]  ;            // add to the frequency count  
 

Копировать в вектор:

 vector<pair<char, int>> res;
std::copy(m.begin(), m.end(), std::back_inserter(res));        
 

И отсортируйте его:

 std::sort(res.begin(), res.end(), [](auto a, auto b) {
    return a.second < b.second;
});
 

Вот демонстрация.

Комментарии:

1. Большое спасибо за ответ. Это именно то, что мне было нужно. И кажется, что использование map намного короче и экономичнее по времени, чем моя идея для этого. Как я уже сказал, я новичок в C , и до сих пор я программировал только на Java, поэтому я иногда теряюсь в синтаксисе и не всегда понимаю, для чего предназначены некоторые функции. Тем не менее, это отличный ответ, и он многое объясняет в функциональности map. Еще раз спасибо.

2. @Insekure Нет проблем, рад помочь 🙂 Как сказал Пол в комментарии выше, обязательно приложите усилия, чтобы понять решение и почему оно работает. Это будет действительно полезно в долгосрочной перспективе.

3. Я знаю, вот почему я здесь прошу помощи и лучших решений, а не просто прошу некоторых моих друзей сделать это за меня. Я хочу это понять, и я это сделаю — мне просто нужно немного почитать об этом и получить более глубокие знания. Еще раз спасибо.

4. @Insekure auto Это просто ярлык, но очень полезный. Вы также могли бы сделать это длинным путем, используя (const std::pair<char,int>amp; a, const std::pair<char,int>amp; b) , но вы видите, насколько это длиннее.

5. @Insekure КСТАТИ, в Java решение будет использовать тот же подход. «Список» для отслеживания символов и количества, аналогичный std::map , и скопировать результаты в массив для сортировки.