Доступ к разделенному вектору на карте - PullRequest
0 голосов
/ 02 сентября 2018

У меня есть входной файл, который имеет следующую структуру

#Latitude   Longitude   Depth [m]   Bathy depth [m] CaCO3 [%] ...
-78 -177    0   693 1
-78 -173    0   573 2
.
.

Я создал карту, ключ которой основан на string (название океанического бассейна ) и на значении, которое содержит вектор данных. Теперь мне нужно отсортировать векторы по bathyDepth. Чтобы быть точным, я хотел бы разделить векторы, чтобы иметь возможность разделить все строки данных с глубиной от 0 до 500m, 500m и 1500m, 1000m и 2000m. ..

Я сохранил данные в структуре map , но я не уверен, как сохранить раздел и получить к нему доступ, чтобы я мог cout указать точку данных на определенной глубине.

Моя попытка:

//Define each basin spatially
//North Atlantic
double NAtlat1 = 0,  NAtlong1 = -70, NAtlat2 = 75, NAtlong2 = -15;
//South Atlantic and the rest...
double SPLIT = 0;

struct Point
{
   //structure Sample code/label--Lat--Long--SedimentDepth[m]--BathymetricDepth[m]--CaCO3[%]--CO3freefraction (SiO2 carb free)[%]--biogenic silica (bSiO2)[%]--Quartz[%]--CO3 ion[umol/l]--CO3critical[umol/l]--Delta CO3 ion[umol/kg]--Ref/source
   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);
};

//MAIN FUNCTION
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 insert() for all other 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;} );
    }
}

Примечание: a относится к типу Point. Если я пытаюсь сохранить itp в структуре, такой как вектор, я получаю следующую ошибку:

error: no matching function for call to ‘std::vector<Point>::push_back(__gnu_cxx::__normal_iterator<Point*, std::vector<Point> >&)’

Я просто не уверен, как хранить itp. Конечной целью является вычисление расстояния между точкой данных и всеми другими точками данных в пределах определенного окна глубины (например, от 1500m до 2500m). Любая помощь для этого новичка будет оценена.

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

Во-первых, давайте сделаем простой случай, который расскажет о вашей проблеме:

struct Point { int bathyDepth; }; // this is all, what you need to show    

int main()
{
    // some points
    Point a{ 1 }, b{ 100 }, c{ 1000 }, d{ 2000 }, e{ 3000 }, f{ 4000 }, g{ 4501 }, h{ 400 }, i{ 1600 }, j{ 2200 }, k{ 700 };
    // one map element
    std::map<std::string, std::vector<Point> > seamap
    { {"Nat", std::vector<Point>{a, b, c, d, e, f, g, h, i, j, k}} };

    //Partition basins by depth
    for (auto it2= seamap.begin(); it2!= seamap.end(); ++it2)
    {
        int i = 500; // some range
        auto itp = std::partition(it2->second.begin(), it2->second.end(), [&i](const auto &a) {return a.bathyDepth < i; });    
    }

    return 0;
}

Я просто не уверен, как хранить itp.

Для хранения нужно знать только его тип. что равно decltype(it2->second)::iterator, так как std::partition возвращает тип контейнера итератора.

Так как key_type вашей карты равен std::vector<Point>, он равен std::vector<Point>::iterator

Вы можете проверить это программно:

if (std::is_same<decltype(it2->second)::iterator, decltype(itp)>::value)
   std::cout << "Same type";

Это означает, что вы можете хранить itp в

using itpType = std::vector<Point>::iterator;
std::vector<itpType> itpVec;
// or any other containers, with itpType

Конечной целью является вычисление расстояния между точкой данных и всеми другие точки данных в конкретном окне глубины (например, от 1500 до 2500м).

Если это так, вам нужно просто отсортировать значения карты (std::vector<Point>) по bathyDepth и выполнить итерацию по ней, чтобы найти необходимый диапазон. Когда вы используете std::partition, внутри этого цикла

for (int i = 500; i<=4500; i+=500 )

конечный эффект / результат такой же, как сортировка сразу, но вы делаете это шаг за шагом. Также обратите внимание, что для получения правильного результата с помощью std::partition вам нужно отсортировать std::vector<Point>.

Например, см. пример кода здесь , который напечатает диапазон, как вы упомянули.

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm>

struct Point
{
    int bathyDepth;
    // provide a operator< for std::sort()
    bool operator<(const Point &rhs)const { return this->bathyDepth < rhs.bathyDepth; }
};
// overloaded  << operator for printing #bathyDepth
std::ostream& operator<<(std::ostream &out, const Point &point) { return out << point.bathyDepth; }

//function for printing/ acceing the range
void printRange(const std::vector<Point>& vec, const int rangeStart, const int rangeEnd)
{
    for (const Point& element : vec)
    {
        if (rangeStart <= element.bathyDepth && element.bathyDepth < rangeEnd) std::cout << element << " ";
        else if (element.bathyDepth > rangeEnd) break; // no need for further checking
    }
    std::cout << "\n";
}

int main()
{
    Point a{ 1 }, b{ 100 }, c{ 1000 }, d{ 2000 }, e{ 3000 }, f{ 4000 }, g{ 4501 }, h{ 400 }, i{ 1600 }, j{ 2200 }, k{ 700 };
    std::map<std::string, std::vector<Point> > seamap
    { {"Nat", std::vector<Point>{a, b, c, d, e, f, g, h, i, j, k}} };

    for (auto it2 = seamap.begin(); it2 != seamap.end(); ++it2)
    {
        // sort it
        std::sort(it2->second.begin(), it2->second.end());
        //Partition basins by depth
        for (int i = 0; i < 4500; i += 500)  printRange(it2->second, i, i + 500);
    }
    return 0;
}

Выход:

1 100 400 
700 
1000 
1600 
2000 2200 
                      // no elements in this range
3000 
                      // no elements in this range
4000
0 голосов
/ 02 сентября 2018

std :: partition возвращает итератор в точке разделения между группами разделенных элементов, которая является первым элементом второй группы. Если вы хотите сохранить это в другом vector, тип вектора должен быть

std::vector<std::vector<Point>::iterator>

То, как вы его используете, при последующих вызовах разбиения вы не хотите разбивать весь вектор, только часть его на более крупные элементы (потому что ранние элементы в векторе теперь являются нижними элементами, вам не нужно включать их в последующие вызовы разделов, поскольку они находятся там, где они должны быть, и в описании partition нет ничего, что говорило бы, что они не будут перемещены). Таким образом, первым элементом в последующих итерациях вашего цикла i должен быть итератор itp, возвращенный во время предыдущего цикла.

...