Я нахожусь в процессе анализа набора данных, который выглядит следующим образом
#Latitude Longitude Depth [m] Bathy depth [m] CaCO3 [%] ...
-78 -177 0 693 1
-78 -173 0 573 2
.
.
План состоит в том, чтобы иметь возможность считывать данные в вектор, а затем разбивать их на различные группы «глубины Бати» (батиметрической глубины). Это также должно быть одновременно сгруппировано в различные океанские бассейны. Например, все точки данных в Северной Атлантике, которые также находятся между BathyDepth 500-1500 м, 1000-2000 м, 1500-2500 м ... должны быть в своей собственной группе (возможно, вектор или другой объект). Идея состоит в том, чтобы иметь возможность выводить их в разные текстовые файлы.
Я пытался сделать это в несколько запутанной манере. Вы можете увидеть это ниже
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <string>
#include <GeographicLib/Geodesic.hpp> //Library which allows for distance calculations
using namespace std;
using namespace GeographicLib;
//Define each basin spatially
//North Atlantic
double NAtlat1 = 1, NAtlong1 = 1, NAtlat2 = 2, NAtlong2=2; //Incorrect values, to be set later
//South Atlantic
double SAtlat1 = 1, SAtlong1 = 1, SAtlat2 = 2, SAtlong2=2;
//North Pacific and the all others...
struct Point
{
//structure Sample code/label--Lat--Long--SedimentDepth[m]--BathymetricDepth[m]--CaCO3[%]...
string dummy;
double latitude, longitude, rockDepth, bathyDepth, CaCO3, fCaCO3, bSilica, Quartz, CO3i, CO3c, DCO3;
string dummy2;
//Use Overload>> operator
friend istream& operator>>(istream& inputFile, Point& p);
};
//Overload operator
istream& operator>>(istream& inputFile, Point& p)
{
string row_text;
//Read line from input, store in row_text
getline(inputFile, row_text);
//Extract line, store in ss row_stream
istringstream row_stream(row_text);
//Read-in data into each variable
row_stream >> p.dummy >> p.latitude >> p.longitude >> p.rockDepth >> p.bathyDepth >> p.CaCO3 >> p.fCaCO3 >> p.bSilica >> p.Quartz >> p.CO3i >> p.CO3c >> p.DCO3 >> p.dummy2;
return inputFile;
}
int main ()
{
//Geodesic class.
const Geodesic& geod = Geodesic::WGS84();
//Input file
ifstream inputFile("Data.csv");
//Point-type vector to store all data
vector<Point> database;
//bathDepth515 = depths between 500m and 1500m
vector<Point> bathyDepth515;
vector<Point> bathyDepth1020; //Create the rest too
Point p;
if (inputFile)
{
while(inputFile >> p)
{
database.push_back(p);
}
inputFile.close();
}
else
{
cout <<"Unable to open file";
}
for(int i = 0; i < database.size(); ++i)
{
//Group data in database in sets of bathyDepth
if(database[i].bathyDepth >= 500 && database[i].bathyDepth < 1500)
{
//Find and fill particular bathDepths
bathyDepth515.push_back(database[i]);
}
if(database[i].bathyDepth >= 1000 && database[i].bathyDepth < 2000)
{
bathyDepth1020.push_back(database[i]);
}
//...Further conditional statements based on Bathymetric depth, could easily include a spatial condition too...
//Calculate distance between point i and all other points within 500-1500m depth window. Do the same with all other windows.
for(int i = 0; i < bathyDepth515.size(); ++i)
{
for(int j = 0; j < bathyDepth515.size(); ++j)
{
double s12;
if(i != j)
{
geod.Inverse(bathyDepth515[i].latitude, bathyDepth515[i].longitude, bathyDepth515[j].latitude, bathyDepth515[j].longitude, s12);
}
}
}
return 0;
}
Задача 1:
Я думаю, что ясно, что некоторые методологии не являются объектно-ориентированными. Например, может быть лучший способ назначить все данные Point
определенному океанскому бассейну, вместо того, чтобы вручную вводить их в начале моей программы, как я делал это при группировании данных по глубине. Я начал создавать класс бассейна с методами для определения местоположения и определениями длины / долготы каждого бассейна, но не очень далеко нашел интуитивный способ сделать это. Я хотел бы, чтобы кто-то дал мне представление о том, как лучше это построить. Моя попытка построить (очень хрупкий) класс выглядит следующим образом
class Basin
{
public:
Basin();
Basin(double latit1, double longit1, double latit2, double longit2);
double getLatitude();
...
private:
double NAt, SAt, NPac, SPac; //All basins
double latitude1, longitude1, latitude2, longitude2; // Boundaries defined by two latitude markers, and two longitude markers.
};
class NAt: public Basin{...}
//...Build class definitions...
Задача 2:
Моя вторая проблема - это метод, в котором я создал векторы для окон различной глубины. Это может стать очень громоздким, если мне придется изменить способ разделения глубин или добавить больше глубин. Мне бы не хотелось менять почти все части моей программы, просто чтобы приспособиться к тому, как я решил сдвинуть окна глубины. Я был бы признателен, если бы кто-нибудь дал мне несколько идей о том, как это сделать.
Единственное решение, которое я мог придумать для проблемы 2, заключается в следующем
//Vector of vectors to store each rows' entries separately. Not sure if this is needed as my `Point` `Struct` already allows for each of the entries in a row to be accessed.
vector<vector<Point> > database;
//Create database vectors for different bathDepth windows, eventhough their names will be the same, once push_back, it doesn't matter
for(int i = 1*500; i<=8*500; i+=500)
{
vector<Point> bathDepthi;
//Possibly push these back into database. These can then be accessed and populated using if statements.
}
//Create vectors individually, creating vector of vectors would be more elegant as I won't have to create more if one were to decide to change the range, I'd just have to change the for loop.
Я не знаю, насколько сильно мои попытки помочь мне, но я подумал, что мог бы дать лучшее представление о том, что я пытаюсь достичь. Извиняюсь за столь длинный пост.
ПЕРЕКЛЮЧАТЕЛЬ РЕДАКЦИИ-ДИЗАЙНА ОТ std::vector
ДО std::map
Основываясь на информации, полученной от размещенного ответа Хеке, я попробовал следующее, но я не уверен, что именно это имел в виду указанный пользователь. Я решил использовать условные операторы, чтобы определить, находится ли точка в конкретном бассейне. Если моя попытка верна, я все еще не уверен, как поступить, если это правильно. В частности, я не уверен, как хранить для доступа к разделенным векторам, скажем, записывать их в отдельные текстовые файлы (т.е. файлы .txt для другой батиметрической глубины). Должен ли я хранить итератор разбиения в векторе, если так, какого типа? Итератор объявлен с auto
, что смущает меня относительно того, как объявить тип вектора для хранения этого итератора.
Моя попытка:
std::map<std::string, std::vector<Point> > seamap;
seamap.insert( std::pair<std::string, std::vector<Point> > ("Nat", vector<Point>{}) );
seamap.insert( std::pair<std::string, std::vector<Point> > ("Sat", vector<Point>{}) ); //Repeat for all ocean basins
Point p;
while (inputFile >> p && !inputFile.eof() )
{
//Check if Southern Ocean
if (p.latitude > Slat2)
{
//Check if Atlantic, Pacific, Indian...
if (p.longitude >= NAtlong1 && p.longitude < SAtlong2 && p.latitude > SPLIT)
{
seamap["Nat"].push_back(p);
} // Repeat for different basins
}
else
{
seamap["South"].push_back(p);
}
}
//Partition basins by depth
for ( std::map<std::string, std::vector<Point> >::iterator it2 = seamap.begin(); it2 != seamap.end(); it2++ )
{
for ( int i = 500; i<=4500; i+=500 )
{
auto itp = std::partition( it2->second.begin(), it2->second.end(), [&i](const auto &a) {return a.bathyDepth < i;} );
}
}