Read a Line From File and Push Into Vector in C++

As a data scientist, reading and writing data from/to CSV is one of the most common tasks I do on the daily. R, my language of choice, makes this easy with read.csv() and write.csv() (although I tend to utilize fread() and fwrite() from the data.table package).

Hot Take . C++ is not R.

As far every bit I know, there is no CSV reader/writer built into the C++ STL. That'south non a knock confronting C++; it'south just a lower level language. If we want to read and write CSV files with C++, nosotros'll have to deal with File I/O, data types, and some low level logic on how to read, parse, and write data. For me, this is a necessary pace in society to build and test more fun programs similar auto learning models.

Writing to CSV

We'll get-go by creating a simple CSV file with ane column of integer data. And we'll give it the header Foo.

                          #include              <fstream>                                                        int              main              ()              {              // Create an output filestream object                                          std              ::              ofstream              myFile              (              "foo.csv"              );              // Send data to the stream                                          myFile              <<              "Foo              \n              "              ;              myFile              <<              "1              \north              "              ;              myFile              <<              "two              \n              "              ;              myFile              <<              "3              \due north              "              ;              // Close the file                                          myFile              .              close              ();              return              0              ;              }                      

Here, ofstream is an "output file stream". Since it's derived from ostream, we can treat information technology just similar cout (which is too derived from ostream). The result of executing this program is that we get a file called foo.csv in the same directory as our executable. Let's wrap this into a write_csv() function that'southward a little more than dynamic.

                          #include              <string>                                          #include              <fstream>                                          #include              <vector>                                                        void              write_csv              (              std              ::              string              filename              ,              std              ::              string              colname              ,              std              ::              vector              <              int              >              vals              ){              // Make a CSV file with 1 cavalcade of integer values                                          // filename - the name of the file                                          // colname - the name of the one and just column                                          // vals - an integer vector of values                                          // Create an output filestream object                                          std              ::              ofstream              myFile              (              filename              );              // Send the column name to the stream                                          myFile              <<              colname              <<              "              \n              "              ;              // Send data to the stream                                          for              (              int              i              =              0              ;              i              <              vals              .              size              ();              ++              i              )              {              myFile              <<              vals              .              at              (              i              )              <<              "              \n              "              ;              }              // Shut the file                                          myFile              .              shut              ();              }              int              main              ()              {              // Make a vector of length 100 filled with 1s                                          std              ::              vector              <              int              >              vec              (              100              ,              1              );              // Write the vector to CSV                                          write_csv              (              "ones.csv"              ,              "Col1"              ,              vec              );              return              0              ;              }                      

Cool. Now nosotros can utilize write_csv() to write a vector of integers to a CSV file with ease. Permit's aggrandize on this to support multiple vectors of integers and corresponding column names.

                          #include              <cord>                                          #include              <fstream>                                          #include              <vector>                                          #include              <utility> // std::pair                                                        void              write_csv              (              std              ::              cord              filename              ,              std              ::              vector              <              std              ::              pair              <              std              ::              string              ,              std              ::              vector              <              int              >>>              dataset              ){              // Make a CSV file with one or more columns of integer values                                          // Each cavalcade of information is represented by the pair <cavalcade proper name, column data>                                          //   as std::pair<std::string, std::vector<int>>                                          // The dataset is represented as a vector of these columns                                          // Note that all columns should exist the same size                                          // Create an output filestream object                                          std              ::              ofstream              myFile              (              filename              );              // Ship cavalcade names to the stream                                          for              (              int              j              =              0              ;              j              <              dataset              .              size              ();              ++              j              )              {              myFile              <<              dataset              .              at              (              j              ).              beginning              ;              if              (              j              !=              dataset              .              size              ()              -              1              )              myFile              <<              ","              ;              // No comma at end of line                                          }              myFile              <<              "              \n              "              ;              // Ship data to the stream                                          for              (              int              i              =              0              ;              i              <              dataset              .              at              (              0              ).              2d              .              size              ();              ++              i              )              {              for              (              int              j              =              0              ;              j              <              dataset              .              size              ();              ++              j              )              {              myFile              <<              dataset              .              at              (              j              ).              2nd              .              at              (              i              );              if              (              j              !=              dataset              .              size              ()              -              1              )              myFile              <<              ","              ;              // No comma at end of line                                          }              myFile              <<              "              \n              "              ;              }              // Close the file                                          myFile              .              shut              ();              }              int              master              ()              {              // Make three vectors, each of length 100 filled with 1s, 2s, and 3s                                          std              ::              vector              <              int              >              vec1              (              100              ,              one              );              std              ::              vector              <              int              >              vec2              (              100              ,              2              );              std              ::              vector              <              int              >              vec3              (              100              ,              3              );              // Wrap into a vector                                          std              ::              vector              <              std              ::              pair              <              std              ::              string              ,              std              ::              vector              <              int              >>>              vals              =              {{              "One"              ,              vec1              },              {              "Ii"              ,              vec2              },              {              "Three"              ,              vec3              }};              // Write the vector to CSV                                          write_csv              (              "three_cols.csv"              ,              vals              );              return              0              ;              }                      

Hither we've represented each column of data equally a std::pair of <column name, column values>, and the whole dataset equally a std::vector of such columns. Now we tin can write a variable number of integer columns to a CSV file.

Reading from CSV

Now that we've written some CSV files, let's attempt to read them. For now permit'due south correctly assume that our file contains integer data plus ane row of column names at the top.

                          #include              <string>                                          #include              <fstream>                                          #include              <vector>                                          #include              <utility> // std::pair                                          #include              <stdexcept> // std::runtime_error                                          #include              <sstream> // std::stringstream                                                        std              ::              vector              <              std              ::              pair              <              std              ::              string              ,              std              ::              vector              <              int              >>>              read_csv              (              std              ::              string              filename              ){              // Reads a CSV file into a vector of <string, vector<int>> pairs where                                          // each pair represents <column proper name, column values>                                          // Create a vector of <string, int vector> pairs to shop the result                                          std              ::              vector              <              std              ::              pair              <              std              ::              cord              ,              std              ::              vector              <              int              >>>              result              ;              // Create an input filestream                                          std              ::              ifstream              myFile              (              filename              );              // Make sure the file is open up                                          if              (              !              myFile              .              is_open              ())              throw              std              ::              runtime_error              (              "Could not open up file"              );              // Helper vars                                          std              ::              string              line              ,              colname              ;              int              val              ;              // Read the column names                                          if              (              myFile              .              good              ())              {              // Extract the first line in the file                                          std              ::              getline              (              myFile              ,              line              );              // Create a stringstream from line                                          std              ::              stringstream              ss              (              line              );              // Extract each cavalcade name                                          while              (              std              ::              getline              (              ss              ,              colname              ,              ','              )){              // Initialize and add <colname, int vector> pairs to event                                          event              .              push_back              ({              colname              ,              std              ::              vector              <              int              >              {}});              }              }              // Read data, line by line                                          while              (              std              ::              getline              (              myFile              ,              line              ))              {              // Create a stringstream of the current line                                          std              ::              stringstream              ss              (              line              );              // Keep track of the current column index                                          int              colIdx              =              0              ;              // Extract each integer                                          while              (              ss              >>              val              ){              // Add together the current integer to the 'colIdx' column's values vector                                          result              .              at              (              colIdx              ).              second              .              push_back              (              val              );              // If the adjacent token is a comma, ignore it and motion on                                          if              (              ss              .              peek              ()              ==              ','              )              ss              .              ignore              ();              // Increment the cavalcade index                                          colIdx              ++              ;              }              }              // Close file                                          myFile              .              shut              ();              return              effect              ;              }              int              main              ()              {              // Read three_cols.csv and ones.csv                                          std              ::              vector              <              std              ::              pair              <              std              ::              string              ,              std              ::              vector              <              int              >>>              three_cols              =              read_csv              (              "three_cols.csv"              );              std              ::              vector              <              std              ::              pair              <              std              ::              string              ,              std              ::              vector              <              int              >>>              ones              =              read_csv              (              "ones.csv"              );              // Write to another file to check that this was successful                                          write_csv              (              "three_cols_copy.csv"              ,              three_cols              );              write_csv              (              "ones_copy.csv"              ,              ones              );              return              0              ;              }                      

This program reads our previously created CSV files and writes each dataset to a new file, essentially creating copies of our original files.

Going further

And then far we've seen how to read and write datasets with integer values but. Extending this to read/write a dataset of only doubles or only strings should be fairly straight-forward. Reading a dataset with unknown, mixed information types is another animal and beyond the scope of this article, but encounter this code review for possible solutions.

Special thanks to papagaga and Incomputable for helping me with this topic via codereview.stackexchange.com.

cartwrightarage1945.blogspot.com

Source: https://www.gormanalysis.com/blog/reading-and-writing-csv-files-with-cpp/

0 Response to "Read a Line From File and Push Into Vector in C++"

Postar um comentário

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel