Возникла трудность при решении такой задачи: дан массив строк, в котором записаны имена и фамилии пользователей.
Нужно вывести пользователей с одинаковыми именами (их имя и фамилию).
Для получения имени из строки я написал специальную функцию, т.к. использовать 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
Почему так происходит я понимаю. Подскажите, как реализовать эту программу правильно.
Спасибо!
Лучше всего завести контейнер вида
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;
}
В простейшем случае, если почти ничего не менять в программе, то достаточно ввести массив логических значений, помечать элементы при выводе, выводить только непомеченные, и в первом цикле помеченные пропускать.
Выделение *curName
стоит вынести из внутреннего цикла.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Программа находит в строке char последовательности одинаковых символов длинной более 3 символов(кроме пробела) и закидывает эти фрагменты...
Я использую примерТут выводятся положения точки на экране :
В каком порядке пройдет инициализация членов класса в С++? Сначала будет вызван конструктор класса или сначала будут проиницилазованы члены-класса?