Accelerated C++ Chapter05 Exercise 5-1編
ドウモデス。
Exercise 5-1を綺麗にしようと試行錯誤していて,簡潔になる方法を思いついたので,
実装していたら,途中で,うまくいかないことに気づいてしばし心折れました。
結局,最初に解いた汚い解答を載せる次第となったこと,ここに深く詫びるでござる。
というか,1問1問の答えがでかくなってきたので,分割しつついきます。
なので,ここでは,Exercise 5-1だけ。
Exercise 5-1
ex5-1.hh
#ifndef GUARD_EX5_1_H #define GUARD_EX5_1_H #include <string> #include <vector> #include <list> #include <algorithm> struct Line { std::string line; std::string rotated_line; std::string index; }; // clean up needed. I hate all these `::'s std::list<std::string> rotate(const std::list<std::string>& l); std::string rotate(const std::string& s); std::vector<std::string> split_into_vec(const std::string&); std::vector<std::string> get_all_rotations(const std::string& s); bool cmp(const Line&, const Line&); void sort_rotations(std::vector<Line> &vec); void print_permuted_line(const std::vector<std::string>&, const std::string&, std::string::size_type); void print_permuted_lines(const std::vector<std::string>& original_lines); std::string str_from_list(const std::list<std::string>& l); std::string::size_type get_maxlen(const std::vector<std::string>&); #endif // GUARD_EX5_1_H
ex5-1.cc
#include <iostream> #include <string> #include <list> #include <vector> #include <algorithm> #include <cctype> #include "ex5-1.hh" using namespace std; string::size_type get_maxlen(const vector<string>& lines) { string::size_type ret = 0; for (vector<string>::const_iterator it = lines.begin(); it != lines.end(); ++it) { string::size_type len = it->length(); if (len > ret) { ret = len; } } return ret; } list<string> rotate(const list<string>& l) { list<string> ret; list<string>::const_iterator it = l.begin(); list<string>::const_iterator beg = l.begin(); ++it; for (; it != l.end(); ++it) { ret.push_back(*it); } ret.push_back(*beg); return ret; } string rotate(const string& s) { string ret; vector<string> v = split_into_vec(s); list<string> l(v.begin(), v.end()); l = rotate(l); return str_from_list(l); } string str_from_list(const list<string>& l) { string ret; for (list<string>::const_iterator it = l.begin(); it != l.end(); ++it) { ret += *it; if (it != --l.end()) { ret += " "; } } return ret; } vector<string> split_into_vec(const string& s) { vector<string> ret; string::const_iterator it = s.begin(); while (it != s.end()) { while (it != s.end() && isspace(*it)) { ++it; } string::const_iterator beg = it; while (it != s.end() && !isspace(*it)) { ++it; } if (beg != it) { ret.push_back(string(beg, it)); } } return ret; } vector<string> get_all_rotations(const string& s) { vector<string> ret; vector<string> splited = split_into_vec(s); // Of course, we need the original line ret.push_back(s); string rotated = s; // Get each rotated string and store it into vector for (int i = 0, j = splited.size() - 1; i < j; ++i) { rotated = rotate(rotated); ret.push_back(rotated); } return ret; } bool cmp(const Line& l1, const Line& l2) { string key1 = l1.rotated_line; transform(key1.begin(), key1.end(), key1.begin(), (int (*)(int))toupper); string key2 = l2.rotated_line; transform(key2.begin(), key2.end(), key2.begin(), (int (*)(int))toupper); return key1.compare(key2) < 0; } void sort_rotations(vector<Line> &vec) { sort(vec.begin(), vec.end(), cmp); } // @lines lines[0] => "The quick brown fox", // lines[1] => "jumped over the fence", etc... void print_permuted_lines(const vector<string>& lines) { vector<Line> sorted_lines; for (vector<string>::const_iterator it = lines.begin(); it != lines.end(); ++it) { // Get all rotations of this line vector<string> v = get_all_rotations(*it); // For each rotation, store the index and its line into vector. for (vector<string>::const_iterator iter = v.begin(); iter != v.end(); ++iter) { string index = split_into_vec(*iter).front(); Line line; line.line = *it; line.index = index; line.rotated_line = *iter; sorted_lines.push_back(line); } } sort_rotations(sorted_lines); string::size_type maxlen = get_maxlen(lines); for (vector<Line>::const_iterator it = sorted_lines.begin(); it != sorted_lines.end(); ++it) { vector<string> splited = split_into_vec(it->line); print_permuted_line(splited, it->index, maxlen); } } void print_permuted_line(const vector<string>& line, const string& index, string::size_type maxlen) { string former, latter; const string separator = " | "; vector<string>::const_iterator it = line.begin(); for (; it != line.end() && it->compare(index) != 0; ++it) { former += *it; if (it != line.end() - 1 && it[1] != index) { former += " "; } } // this is index latter += *it; // and the rest for (++it; it != line.end(); ++it) { latter += " " + *it; } cout << string(maxlen - former.size(), ' ') << former; cout << separator; cout << latter; cout << endl; }
デモ用メイン ex5-1_main.cc マインちゃん。えっ。
#include <iostream> #include <string> #include <vector> #include <list> #include "ex5-1.hh" using namespace std; int main() { string s; vector<string> vec; while (getline(cin, s)) { vec.push_back(s); } print_permuted_lines(vec); return 0; }
実行結果
% echo "The quick brown fox\njumped over the fence" | ./ex5-1_demo The quick | brown fox jumped over the | fence The quick brown | fox | jumped over the fence jumped | over the fence The | quick brown fox jumped over | the fence | The quick brown fox
おまけ
すごくメモリを贅沢に使っていることはわかっちゃーいるんですが,
いいデータ構造を思いつかないし,知らない。いや,凡夫だから,
知らないから思いつかないのか。
オリジナルの行とインデックスの対応を持っておかないと,
出力するときに困るから,オリジナルの行は必要だし,
すべて読み込んだ後にソートするから,ローテーションも全部必要だし・・・。
うーん,わからん。