Сортировка .csv в многомерных массивах - PullRequest
1 голос
/ 06 июня 2019

Я пытаюсь прочитать конкретные значения (то есть значения @ координаты XY) из файла .csv и пытаюсь найти правильный способ определения многомерных массивов в этом .csv.

Вот пример формыиз моего файла .csv

NaN,NaN,1.23,2.34,9.99
1.23,NaN,2.34,3.45,NaN
NaN,NaN,1.23,2.34,9.99
1.23,NaN,2.34,3.45,NaN
1.23,NaN,2.34,3.45,NaN

NaN,NaN,1.23,2.34,9.99
1.23,NaN,2.34,3.45,NaN
NaN,NaN,1.23,2.34,9.99
1.23,NaN,2.34,3.45,NaN
1.23,NaN,2.34,3.45,NaN

NaN,NaN,1.23,2.34,9.99
1.23,NaN,2.34,3.45,NaN
NaN,NaN,1.23,2.34,9.99
1.23,NaN,2.34,3.45,NaN
1.23,NaN,2.34,3.45,NaN

...

Хорошо, в действительности этот файл становится очень большим.Вы можете интерпретировать строки = широты и столбцы = долготы, и, таким образом, каждый блок представляет собой почасово измеренную карту координат.Блоки обычно имеют размер столбца строки [361] [720], а периоды времени могут составлять до 20 лет (= 24 * 365 * 20 блоков), просто чтобы дать вам представление о размере данных.

Чтобы структурировать это, я подумал о сканировании через .csv и определил каждый блок как вектор t, к которому я могу получить доступ, выбрав желаемый временной шаг t = 0,1,2,3 ...

Затемв этом блоке я хотел бы перейти к конкретной линии (то есть широте) и определить ее как вектор longitudeArray.

Результатом должно быть указанное значение из координаты XY в момент времени Z.

Как вы можете догадаться, мой опыт кодирования довольно ограничен, и поэтому мой фактический вопрос может быть очень простым: как я могу расположить свои векторы, чтобы иметь возможность вызывать любое случайное значение?

Это мойпока код (к сожалению, это не так много, потому что я не знаю, как продолжить ...)

#include <fstream>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>


using namespace std;


int main()
{   
  int longitude, latitude;                //Coordinates used to specify desired value
  int t;                                  //Each array is associated to a specific time t=0,1,2,3... (corresponds to hourly measured data)
  string value;                           

  vector<string> t;                       //Vector of each block
  vector<string> longitudeArray;          //Line of array, i.e. latitude    

  ifstream file("swh.csv");               //Open file
  if (!file.is_open())                    //Check if file is opened, if not 
  print "File could..."
  {
     cout << "File could not open..." << endl;
     return 1;
  }

  while (getline(file, latitude, latitude.empty()))   //Scan .csv (vertically) and delimit every time a white line occurs
  {
     longitudeArray.clear();
     stringstream ss(latitude);

     while(getline(ss,value,',')         //Breaks line into comma delimited fields //Specify line number (i.e. int latitude) here??
     {
        latitudeArray.push_back(value); //Adds each field to the 1D array //Horizontal vector, i.e. latitude
     }
     t.push_back(/*BLOCK*/)              //Adds each block to a distinct vector t
  }
  cout << t(longitudeArray[5])[6] << endl;    //Output:   5th element of longitudeArray in my 6th block

  return 0;

}

Если у вас есть какие-либо подсказки, особенно если естьлучший способ обработки больших файлов .csv, я был бы очень признателен.

Ps: C ++ неизбежен для этого проекта ...

Tüdelüü, jtotheakob

Ответы [ 3 ]

0 голосов
/ 07 июня 2019

Спасибо, я пытался перенести обе версии в мой код, но не смог заставить его работать.Думаю, мои плохие навыки кодирования не в состоянии увидеть то, что очевидно для всех остальных.Можете ли вы назвать дополнительные библиотеки, которые мне могут понадобиться?Для std::isspace мне нужно #include <cctype>, что-нибудь еще отсутствует, что не упомянуто в моем коде сверху?

Можете ли вы также объяснить, как работает if (std::isspace(c) || (c == ',')) std::cin.get();?Из того, что я понимаю, он проверит, является ли c (которое является полем ввода?) Пробелом, и если да, то правильный термин автоматически становится «истинным» из-за ||?Каковы последствия этого?

Наконец, if (! std::cin) break используется для остановки цикла после того, как мы достигли указанного массива [time] [lat] [long]?

В любом случае, спасибо заВаш ответ.Я действительно ценю это, и теперь у меня есть идея, как определить мои циклы.

0 голосов
/ 27 июня 2019

Еще раз спасибо всем за ваши идеи. К сожалению, я не смог запустить скрипт ... но моя задача немного изменилась, поэтому больше не нужно читать очень большие массивы.

Однако у меня есть представление о том, как структурировать такие операции, и, скорее всего, я перенесу это в мою новую задачу.

Вы можете закрыть эту тему сейчас;)

Приветствия

jtothekaob

0 голосов
/ 06 июня 2019

Как обычно, вы должны сначала подумать с точки зрения данных и использования данных. Здесь у вас есть значения с плавающей точкой (которые могут быть NaN), которые должны быть доступны как 3D вещь по широте, долготе и времени.

Если вы можете принять простые (целочисленные) индексы, стандартными способами в C ++ будут необработанные массивы, std::array и std::vector. Эмпирическое правило гласит: если размеры известны во время компиляции (или std::array, если вы хотите работать с глобальными массивами), то все в порядке, в противном случае используйте векторы. И если вы не уверены, std:vector ваша рабочая лошадка.

Так что вы, вероятно, закончите с std::vector<std::vector<std::vector<double>>> data, который вы будете использовать как data[timeindex][latindex][longindex]. Если бы все было статично, вы могли бы использовать double data[NTIMES][NLATS][NLONGS], к которому вы бы обращались более или менее таким же образом. Осторожно, если массив большой, большинство компиляторов захлебнется, если вы объявите его внутри функции (включая main), но он может быть глобальным внутри одной единицы компиляции (C-ish, но все еще действителен в C ++).

Итак, читайте файл построчно, передавая значения в контейнере . Если вы используете статически определенные массивы, просто присваивайте каждое новое значение в его позиции, если вы используете векторы, вы можете динамически добавлять новые элементы с помощью push_back.

Это слишком далеко от вашего текущего кода, чтобы я мог показать вам больше, чем простой код.

Статическая (C-ish) версия может содержать:

#define NTIMES 24*365*20
#define NLATS 361
#define NLONGS 720

double data[NTIMES][NLATS][NLONGS];
...
int time, lat, long;
for(time=0; time<NTIMES; time++) {
    for (lat=0; lat<NLATS; lat++) {
        for (long=0; long<NLONGS; long++) {
            std::cin >> data[time][lat][long];
            for (;;) {
                if (! std::cin) break;
                char c = std::cin.peek();
                if (std::isspace(c) || (c == ',')) std::cin.get();
                else break;
            }
            if (! std::cin) break;
        }
        if (! std::cin) break;
    }
    if (! std::cin) break;
}
if (time != NTIMES) {
    //Not enough values or read error
    ...
}

Более динамическая версия, использующая векторы:

int ntimes = 0;
const int nlats=361;      // may be a non compile time values
const int nlongs=720;     // dito

vector<vector<vector<double>>> data;

int lat, long;

for(;;) {
    data.push_back(vector<vector<double>>);
    for(lat=0; lat<nlats; lat++) {
        data[ntimes].push_back(vector<double>(nlongs));
        for(long=0; long<nlongs; long++) {
            std::cin >> data[time][lat][long];
            for (;;) {
                if (! std::cin) break;
                char c = std::cin.peek();
                if (std::isspace(c) || (c == ',')) std::cin.get();
                else break;
            }
            if (! std::cin) break;
        }
        if (! std::cin) break;
    }
    if (! std::cin) break;
    if (lat!=nlats || long!=nlongs) {
        //Not enough values or read error
        ...
    }
    ntimes += 1;
}

Этот код успешно обработает NaN, преобразовав его в специальное не числовое значение , но он не проверяет количество полей в строке. Для этого прочитайте строку с std::getline и используйте strstream для ее анализа.

...