-
Notifications
You must be signed in to change notification settings - Fork 97
change csv to deal in strings now and convert appended values into strings #625
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,18 +34,54 @@ | |
| #define INCLUDE_SCRIMMAGE_COMMON_CSV_H_ | ||
|
|
||
| #include <fstream> | ||
| #include <iomanip> | ||
| #include <iostream> | ||
| #include <list> | ||
| #include <map> | ||
| #include <memory> | ||
| #include <sstream> | ||
| #include <string> | ||
| #include <utility> | ||
| #include <variant> | ||
|
|
||
| #include "scrimmage/parse/ParseUtils.h" | ||
|
|
||
| namespace { | ||
| struct StringifyVisitor { | ||
|
|
||
| bool double_is_fixed = true; | ||
| bool double_is_scientific = true; | ||
| int double_precision = 13; | ||
|
|
||
| std::string operator()(int value) const { return std::to_string(value); } | ||
| std::string operator()(unsigned int value) const { return std::to_string(value); } | ||
| std::string operator()(size_t value) const { return std::to_string(value); } | ||
| std::string operator()(long value) const { return std::to_string(value); } | ||
| std::string operator()(const std::string& value) const { return value; } | ||
| std::string operator()(bool value) const { return value ? "True" : "False"; } | ||
| std::string operator()(double value) const { | ||
| // default precision values for double are not enough in many cases | ||
| std::ostringstream conv; | ||
| if (double_is_fixed) { | ||
| conv << std::fixed; | ||
| } | ||
| if (double_is_scientific) { | ||
| conv << std::scientific; | ||
| } | ||
| conv << std::setprecision(double_precision) << value; | ||
| return conv.str(); | ||
| } | ||
| }; | ||
| } // namespace | ||
|
|
||
| namespace scrimmage { | ||
|
|
||
| class CSV { | ||
| public: | ||
| typedef std::list<std::string> Headers; | ||
| typedef std::list<std::pair<std::string, double>> Pairs; | ||
| typedef std::variant<bool, size_t, unsigned int, long, int, double, std::string> | ||
|
||
| PossibleVariantTypes; | ||
| typedef std::list<std::pair<std::string, PossibleVariantTypes>> Pairs; | ||
|
|
||
| ~CSV(); | ||
|
|
||
|
|
@@ -75,7 +111,11 @@ class CSV { | |
|
|
||
| size_t rows(); | ||
|
|
||
| double at(int row, const std::string& header); | ||
| template <class T1> | ||
| T1 at(int row, const std::string& header) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see -- now this is where I'd use a size_t, because it's an index. But this ties into existing underlying definitions, so I wouldn't change that now. (Actually, taking a closer look... the table uses an int as a key into a map... wut? Why is it not a vector? And can you have negative column/row indexes? Weird... still -- not something for this update.) |
||
| const int column = column_headers_.at(header); | ||
| return convert<T1>(table_.at(row).at(column)); | ||
| } | ||
|
|
||
| friend std::ostream& operator<<(std::ostream& os, const CSV& csv); | ||
|
|
||
|
|
@@ -87,6 +127,8 @@ class CSV { | |
| void set_double_scientific(bool is_scientific) { double_is_scientific_ = is_scientific; } | ||
|
|
||
| protected: | ||
| std::string get_csv_string(const PossibleVariantTypes& val) const; | ||
|
|
||
| std::list<std::string> get_csv_line_elements(const std::string& str); | ||
|
|
||
| void write_headers(); | ||
|
|
@@ -100,7 +142,7 @@ class CSV { | |
| // Key 1 : Row Index | ||
| // Key 2 : Column Index | ||
| // Value : Cell Value | ||
| std::map<int, std::map<int, double>> table_; | ||
| std::map<int, std::map<int, std::string>> table_; | ||
| int next_row_ = 0; | ||
|
|
||
| std::ofstream file_out_; | ||
|
|
@@ -110,7 +152,6 @@ class CSV { | |
| int double_precision_ = 13; | ||
| bool double_is_fixed_ = true; | ||
| bool double_is_scientific_ = false; | ||
|
|
||
| std::string headers_to_string() const; | ||
| std::string rows_to_string() const; | ||
| std::string row_to_string(const int& i) const; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,16 +30,12 @@ | |
| * | ||
| */ | ||
|
|
||
| #include <fstream> | ||
| #include <iomanip> | ||
| #include <iostream> | ||
| #include <sstream> | ||
| #include "scrimmage/common/CSV.h" | ||
|
|
||
| #include <vector> | ||
|
|
||
| #include <boost/algorithm/string.hpp> | ||
| #include <boost/tokenizer.hpp> | ||
| #include <scrimmage/parse/ParseUtils.h> | ||
| #include "scrimmage/common/CSV.h" | ||
|
|
||
| using std::cout; | ||
| using std::endl; | ||
|
|
@@ -73,14 +69,23 @@ void CSV::set_column_headers(const std::string& headers, bool write) { | |
| set_column_headers(headers_vec, write); | ||
| } | ||
|
|
||
| std::string CSV::get_csv_string(const PossibleVariantTypes& v) const { | ||
| return std::visit( | ||
| StringifyVisitor{ | ||
| .double_is_fixed = double_is_fixed_, | ||
| .double_is_scientific = double_is_scientific_, | ||
| .double_precision = double_precision_}, | ||
| v); | ||
| } | ||
|
|
||
| bool CSV::append(const Pairs& pairs, bool write, bool keep_in_memory) { | ||
|
|
||
| for (std::pair<std::string, double> pair : pairs) { | ||
| for (auto pair : pairs) { | ||
|
||
| auto it = column_headers_.find(pair.first); | ||
| if (it == column_headers_.end()) { | ||
| cout << "Warning: column header doesn't exist: " << pair.first << endl; | ||
| } | ||
| table_[next_row_][it->second] = pair.second; | ||
| table_[next_row_][it->second] = get_csv_string(pair.second); | ||
| } | ||
|
|
||
| if (write) { | ||
|
|
@@ -163,22 +168,7 @@ std::string CSV::row_to_string(const int& row) const { | |
| std::vector<std::string> values(column_headers_.size(), no_value_str_); | ||
| auto it_row = table_.find(row); | ||
| for (auto& kv : it_row->second) { | ||
| if (static_cast<int64_t>(kv.second) == kv.second) { | ||
| values[kv.first] = std::to_string(static_cast<int64_t>(kv.second)); | ||
| } else if (static_cast<double>(kv.second) == kv.second) { | ||
| // default precision values for double are not enough in many cases | ||
| std::ostringstream conv; | ||
| if (double_is_fixed_) { | ||
| conv << std::fixed; | ||
| } | ||
| if (double_is_scientific_) { | ||
| conv << std::scientific; | ||
| } | ||
| conv << std::setprecision(double_precision_) << kv.second; | ||
| values[kv.first] = conv.str(); | ||
| } else { | ||
| values[kv.first] = std::to_string(kv.second); | ||
| } | ||
| values[kv.first] = kv.second; | ||
|
||
| } | ||
|
|
||
| // Append the rows to the resultant string | ||
|
|
@@ -238,7 +228,7 @@ bool CSV::read_csv_from_string(const std::string& csv_str, const bool& contains_ | |
| std::vector<std::string> tokens; | ||
| boost::split(tokens, line, boost::is_any_of(",")); | ||
| for (unsigned int i = 0; i < tokens.size(); i++) { | ||
| table_[row_num][i] = std::stod(tokens[i]); | ||
| table_[row_num][i] = tokens[i]; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is going to be the most annoying thing, and is going to tie into Note that when you handle things like escaped double quotes, those need to be handled via linearly scanning through the string; you can't do global substring substitutions because that may not work the way you expect it to for some cases. |
||
| } | ||
|
|
||
| // If this is the first line and the file doesn't contain a header, | ||
|
|
@@ -284,11 +274,6 @@ size_t CSV::rows() { | |
| return table_.size(); | ||
| } | ||
|
|
||
| double CSV::at(int row, const std::string& header) { | ||
| const int column = column_headers_.at(header); | ||
| return table_.at(row).at(column); | ||
| } | ||
|
|
||
| std::list<std::string> CSV::get_csv_line_elements(const std::string& str) { | ||
| std::list<std::string> elems; | ||
| std::vector<std::string> tokens; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd opt for "true" and "false" (not capitalized). There's not a huge reason for this, but there's also not a huge reason for capitalizing, so my "break the tie" reasoning" is that if people are ever typing it, that's one less thing to mess up. If it's read case-insensitive (which I would hope it is), then no reason to throw in a capital and make people wonder. Python is the only thing I know of that has case-sensitive "True" and "False". No reason to bring that into a CSV.