Вам нужно объединить основную проблему в подзадачи. Исходя из ваших требований необходимы следующие шаги:
- Открыть входной файл
- Считать заголовок файла CSV-файла
- Считать полные данные из файла и проанализировать отдельные строки
- Подсчитайте, сколько друзей у каждого человека
- Сортировка результатов по количеству в порядке убывания
- Запись результата в выходной файл
Все это можно сделать в ~ 25 строках кода. Функция Main состоит из ~ 12 строк. Пожалуйста, смотрите ниже одно возможное решение. Это решение использует библиотеку std.
#include <map>
#include <string>
#include <iostream>
#include <fstream>
#include <utility>
#include <iterator>
#include <regex>
#include <vector>
// Make reading easier
using PairOfFriends = std::pair<const std::string, std::string>; // This is exactly one pair of friends. With a const member for multimap "type_value"
using MmFriend = std::multimap<std::string, std::string>; // And this are all pairs of frineds in a sorted multimap
struct PairLine // ! This is a proxy for the input_iterator !
{ // Input function. Read on line of text file and split it into 2 parts
friend std::istream& operator>>(std::istream& is, PairLine& line)
{ // We will use a regex iterator to be a little more tolerant for different separator characters
std::string wholeLine; std::regex comma("[ \t\n]*[,;.][ \t\n]*");
std::getline(is, wholeLine); // Read one complete line and split it into 2 parts
std::vector<std::string> part{ std::sregex_token_iterator(wholeLine.begin(), wholeLine.end(), comma, -1), std::sregex_token_iterator() };
if (2 == part.size()) line.pairString = std::make_pair(part[0], part[1]); // Copy the 2 parts in our internal variable
return is;
}
operator PairOfFriends() const { return pairString; } // Cast pairString to PairOfFriends. For input iterator.
std::pair<std::string, std::string> pairString{}; // Internal representation. Attention! No const member!
};
struct PersonCount
{ // We will use this POD to store person names and related counts
std::string person; unsigned int personCount; // And we need also an output function
friend std::ostream& operator<< (std::ostream& os, const PersonCount& pc) { return (os << pc.person << "," << pc.personCount); }
};
int main()
{
// 1. Open file. Will be closed by destructor ------------------------------
std::ifstream inFileStream{ "r:\\person.csv" };
// 2. Read header ----------------------------------------------------------
std::string header; std::getline(inFileStream, header);
// 3. Read the complete CSV file and put result into multimap --------------
MmFriend mmFriend{ std::istream_iterator<PairLine>(inFileStream), std::istream_iterator<PairLine>() };
// 4. Count how many friends persons have ----------------------------------
std::vector<PersonCount> friendCount{}; // Person and Count will be stored here
for (MmFriend::iterator it = mmFriend.begin(), end = mmFriend.end(); it != end; it = mmFriend.upper_bound(it->first)) {
friendCount.emplace_back(PersonCount{it->first, mmFriend.count(it->first) }); // Put count info into new arry
}
//5. Sort ------------------------------------------------------------------
std::sort(friendCount.begin(), friendCount.end(), [](const PersonCount & p1, const PersonCount & p2) { return p2.personCount < p1.personCount; });
// 6. Output ---------------------------------------------------------------
std::ofstream outFileStream{"r:\\out.txt"};
outFileStream << "ID,Friend_count\n";
std::copy(friendCount.begin(), friendCount.end(), std::ostream_iterator<PersonCount>(outFileStream, "\n"));
return 0;
}
Обратите внимание: для чтения CSV-данных и их анализа мы используем входной итератор. Весь разбор выполняется в основном в одну строку. Функции Extractor анализируют входную строку с помощью sregex_token_iterator. Если это должно быть расширено до более чем 2 записей, вместо стандартных пар можно использовать кортежи.
Остальное действительно легко. Я думаю, это не нуждается в дополнительном объяснении.
Тем не менее. При необходимости я, конечно, отвечу на вопросы.
Надеюсь, это поможет