Ваш вопрос состоит из 2 частей. И необходимость вкратце поговорить о моделях данных и Excel.
98% людей, работающих с Excel, неправильно используют Excel. Большинство обрабатываемых данных - это реляционные данные. А реляционные данные должны храниться в реляционных базах данных. В Excel было добавлено так много функций и возможностей, как промежуточные итоги или сводные таблицы, чтобы имитировать функциональность базы данных. Но это в основном неправильный подход. Я мог go работать часами, но людям нравится их Excel (я тоже), так что позвольте им это делать.
Ваши данные хранятся в так называемой денормализованной форме или плоской таблице. Это очень хорошо, потому что тогда вы можете использовать сводные таблицы для легкого анализа.
Итак, сначала нам нужно прочитать ваши данные, хранящиеся в файле CSV. Я уже опубликовал массу примеров, как это сделать. Но позвольте мне объяснить еще раз.
Мы будем читать данные из любого потока, например, из потока открытого файла или std::istringstream
.
Это мы делаем с помощью функции std::getline
. Мы читаем всю строку, а затем разбиваем строку на токены. Для этого мы используем std::vector
(для хранения токенов) и std::sregex_token_iterator
для перебора подстрок и их сохранения. Эта часть довольно проста.
Далее, и это наиболее важно, и аналогично выбору правильной модели данных / схемы базы данных, нам нужно подумать о том, как хранить данные.
Если мы смотрим на ввод, у нас есть x-значения. Каждое значение x может иметь 0, 1 или более значений y и z. Итак, у нас есть связь. Кстати. Не каждое значение x должно иметь все значения y. Итак, могут быть такие входные данные:
10,5,0.2
10,6,0.5
10,7,0.6
20,5,0.7
20,6,0.8
20,7,0.9
30,2,0.7
20,8,0.8
Эквивалент реляционных данных в STL может быть разработан с использованием ассоциативного контейнера, например std::map
или std::unordered_map
. Итак, мы выберем тип данных std::map<int, std::map<int, double>>
для правильной обработки исходных данных. Первый тип std::map
- это значение x. И вторая, связанная часть - это снова std::map
со значениями y и z.
После чтения значений и сохранения данных мы получим следующую иерархическую структуру:
содержание карты
Затем для печати нам нужно сначала извлечь все DISTINCT y-значения и сохранить их временно. A std::set
- подходящий контейнер для хранения различных значений. Затем мы напечатаем y-значения в качестве заголовка.
Затем мы напечатаем все c -значения, а затем проверим, существует ли z-значение для текущего y-значения. Если да, то мы его распечатаем.
И все это можно сделать с помощью небольшого фрагмента кода:
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <regex>
#include <set>
const std::regex re{ "," };
std::istringstream sourceFileStream{R"(10,5,0.2
10,6,0.5
10,7,0.6
20,5,0.7
20,6,0.8
20,7,0.9
30,2,0.7
20,8,0.8
)"};
int main() {
std::map<int, std::map<int, double>> data;
// Read values -----------------------------------------------------------------------------------
// Read all lines from source file
for (std::string line{}; std::getline(sourceFileStream, line); ) {
// Split the line into tokens
std::vector token(std::sregex_token_iterator(line.begin(), line.end(), re, -1), {});
// Convert strings to values
const int x{ std::stoi(token[0]) };
const int y{ std::stoi(token[1]) };
const double z{ stod(token[2]) };
// Store values into map
data[x][y] = z;
}
// Print values ----------------------------------------------------------------------------------
// Extract all distinct y values. To get unique values, we will use a std::set
std::set<int> yValues{};
for (const auto& [x, yz] : data) for (const auto& [y, z] : yz) yValues.insert(y);
// Print all y values
for (const int y : yValues) std::cout << '\t' << y;
std::cout << '\n';
// Now iterate over all x values
for (const auto& [x, yz] : data) {
// Print the x-value for this line
std::cout << x;
// Search the z Value for this x value and the y value of the current column
for (const int y : yValues) {
std::cout << '\t';
// If we have a z value for this x value and the current column y value
if (auto it = yz.find(y); it != yz.end()) std::cout << it->second;
}
std::cout << '\n';
}
return 0;
}
Обратите внимание, что строка data[x][y] = z;
находится под капотом , очень сложное заявление. Пожалуйста, уделите время, чтобы глубоко проанализировать и понять это.
Если возникнут какие-либо вопросы, я с радостью отвечу