Вывести данные о людях, имена которых повторяются

130
01 января 2020, 08:30

Возникла трудность при решении такой задачи: дан массив строк, в котором записаны имена и фамилии пользователей.
Нужно вывести пользователей с одинаковыми именами (их имя и фамилию). Для получения имени из строки я написал специальную функцию, т.к. использовать strtok тут не получится - она сохраняет изменения над самой строкой.

template <typename T>
int find(int length, T *arr, T element)
{
    for (int i = 0; i < length; i++)
        if (arr[i] == element)
            return i;
    return -1;
}
char *getWord(char *letter, int delimiterIndex) // получить все слова до разделителя (его индекса)
{
    char *wrds = new char[delimiterIndex];
    strncpy(wrds, letter, delimiterIndex);
    wrds[delimiterIndex] = '\0';
    return wrds;
}
int main()
{
    const int SIZE = 5;
    char users[SIZE][30] =
    {
        "James Smith",
        "George Williams",
        "James Brown",
        "Ann Johnson",
        "James Miller"
    };
    for (int i = 0; i < SIZE - 1; i++) {
        for (int j = i + 1; j < SIZE; j++) {
            // получим текущее и следующее имена из строки
            // в строке имя и фамилия разделены пробелом, потому вытащим слово до первого пробела
            char *curName = getWord(users[i], find(strlen(users[i]), users[i], ' ')); 
            char *nextName = getWord(users[j], find(strlen(users[j]), users[j], ' '));
            if (!strcmp(curName, nextName)) // если имена равны
            { // вывести их
                cout << users[i] << endl;
                cout << users[j] << endl;
            }
        }
    }

    return 0;
}

Чтобы вывести пользователей с одинаковыми именами, я в цикле сравниваю имя из текущей и следующей строк. Если они равны, то вывожу текущую и следующую строки. Проблема следующая, имея такой массив, как у меня, программа выведет такой результат:
James Smith James Brown James Smith James Miller James Brown James Miller
А должна выводить такой:
James Smith James Brown James Miller
Почему так происходит я понимаю. Подскажите, как реализовать эту программу правильно.
Спасибо!

Answer 1

Лучше всего завести контейнер вида

std::map<std::string, std::vector<std::string>> res;

В качестве ключа надо использовать фамилию, а в массив заносить имя/фамилию всех соответствующих людей. В результате должно получиться что-то вроде:

res = {
    "James" => ["James Smith", "James Brown", "James Miller"],
    "George" => ["George Williams"],
    "Ann" => ["Ann Johnson"]
}

И далее надо распечатывать только те массивы, в которых более одного элемента.

Привожу код (C++17):

#include <string>
#include <map>
#include <vector>
#include <iostream>
int main()
{
    std::vector<std::string> users {
        "James Smith",
        "George Williams",
        "James Brown",
        "Ann Johnson",
        "James Miller",
        "Ann Turing",
    };
    std::map<std::string, std::vector<std::string>> res;
    for (auto & name: users) {
        auto first_name = name.substr(0, name.find(' '));
        auto it = res.find(first_name);
        if (it == res.end()) {
            res[first_name] = {name};
        } else {
            it->second.push_back(name);
        }
    }
    for (auto & [name, vec]: res) {        
        if (vec.size() <= 1)
            continue;
        std::cout << "People with name " << name << ":\n";
        for (auto & full_name: vec) {
            std::cout << "\t" << full_name << "\n";
        }
    }
    return 0;
}
Answer 2

В простейшем случае, если почти ничего не менять в программе, то достаточно ввести массив логических значений, помечать элементы при выводе, выводить только непомеченные, и в первом цикле помеченные пропускать.

Выделение *curName стоит вынести из внутреннего цикла.

READ ALSO
Ошибки в коде С++

Ошибки в коде С++

Программа находит в строке char последовательности одинаковых символов длинной более 3 символов(кроме пробела) и закидывает эти фрагменты...

151
Как получить широту и долготу выбранной точки в Arcgis?

Как получить широту и долготу выбранной точки в Arcgis?

Я использую примерТут выводятся положения точки на экране :

134
Ошибка при foreach

Ошибка при foreach

Почему ругается? Хочу пройтись по этим символам циклом

453
C++ порядок инициализации членов-класса

C++ порядок инициализации членов-класса

В каком порядке пройдет инициализация членов класса в С++? Сначала будет вызван конструктор класса или сначала будут проиницилазованы члены-класса?

164