Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- - 因為不知道 AnsiString 是什麼,這裡我先使用 std::string 代替,還請見諒
- - 示範部分,單純為了方面看到內容,存入了 1 跟 0 以外的數值,一切以原 PO 的規格為主
- id 順序的部分啊,我就使用遞增去作了
- 首先,我們來看看這段邏輯
- if(pcs==1)ID_display=bit7;
- if(pcs==2)ID_display=bit7+bit6;
- if(pcs==3)ID_display=bit7+bit6+bit5;
- if(pcs==4)ID_display=bit7+bit6+bit5+bit4;
- if(pcs==5)ID_display=bit7+bit6+bit5+bit4+bit3;
- if(pcs==6)ID_display=bit7+bit6+bit5+bit4+bit3+bit2;
- if(pcs==7)ID_display=bit7+bit6+bit5+bit4+bit3+bit2+bit1; //最多7個
- 讓我們先把他變成一個函數
- std::string unkonwn_logic_a(int pcs, std::string bit0, std::string bit1,
- std::string bit2, std::string bit3,
- std::string bit4, std::string bit5,
- std::string bit6, std::string bit7) {
- if (pcs == 1) return bit7;
- if (pcs == 2) return bit7 + bit6;
- if (pcs == 3) return bit7 + bit6 + bit5;
- if (pcs == 4) return bit7 + bit6 + bit5 + bit4;
- if (pcs == 5) return bit7 + bit6 + bit5 + bit4 + bit3;
- if (pcs == 6) return bit7 + bit6 + bit5 + bit4 + bit3 + bit2;
- if (pcs == 7) return bit7 + bit6 + bit5 + bit4 + bit3 + bit2 + bit1;
- }
- 可以觀察到,事情似乎有些有趣。來改寫一下
- std::string unkonwn_logic_a(int pcs, std::string bit0, std::string bit1,
- std::string bit2, std::string bit3,
- std::string bit4, std::string bit5,
- std::string bit6, std::string bit7) {
- using namespace std::placeholders;
- const auto &rec = std::bind(unkonwn_logic_a, _1, bit0, bit1, bit2, bit3, bit4,
- bit5, bit6, bit7);
- // TODO pcs 小於等於 0 該做些什麼?
- if (pcs == 1) return bit7;
- if (pcs == 2) return rec(1) + bit6;
- if (pcs == 3) return rec(2) + bit5;
- if (pcs == 4) return rec(3) + bit4;
- if (pcs == 5) return rec(4) + bit3;
- if (pcs == 6) return rec(5) + bit2;
- if (pcs == 7) return rec(6) + bit1;
- // TODO pcs 大於 7 該做些什麼?
- }
- 由於是遞迴結構,我們觀察前面兩個看看
- // 當 pcs 為 1 時,我們取尾巴 1 個
- if (pcs == 1) return bit7;
- // 當 pcs 為 2 時,我們取尾巴 2 個
- if (pcs == 2) return rec(1) + bit6;
- 因此我們可以 "合理" 推斷,當 pcs 為 n 時,我們取尾巴 n 個,這樣就完成剛剛的 TODO 了
- (當然,合理因人而異,這裡只是提供一種可能性而已,畢竟原 PO 並沒有提供其他的線索)
- std::string unkonwn_logic_a(int pcs, std::string bit0, std::string bit1,
- std::string bit2, std::string bit3,
- std::string bit4, std::string bit5,
- std::string bit6, std::string bit7) {
- using namespace std::placeholders;
- const auto &rec = std::bind(unkonwn_logic_a, _1, bit0, bit1, bit2, bit3, bit4,
- bit5, bit6, bit7);
- if (pcs <= 0) return "";
- if (pcs == 1) return rec(0) + bit7;
- if (pcs == 2) return rec(1) + bit6;
- if (pcs == 3) return rec(2) + bit5;
- if (pcs == 4) return rec(3) + bit4;
- if (pcs == 5) return rec(4) + bit3;
- if (pcs == 6) return rec(5) + bit2;
- if (pcs == 7) return rec(6) + bit1;
- if (pcs == 8) return rec(7) + bit0;
- return rec(8);
- }
- Ok,現在我們來處理應該要是 ID 但是名字卻是 bit 的變數們,讓我們稍微改變一下寫法
- std::string unkonwn_logic_a(int pcs, std::string ids) {
- using namespace std::placeholders;
- const auto &rec = std::bind(unkonwn_logic_a, _1, ids);
- if (pcs <= 0) return "";
- if (pcs == 1) return rec(0) + ids.at(7);
- if (pcs == 2) return rec(1) + ids.at(6);
- if (pcs == 3) return rec(2) + ids.at(5);
- if (pcs == 4) return rec(3) + ids.at(4);
- if (pcs == 5) return rec(4) + ids.at(3);
- if (pcs == 6) return rec(5) + ids.at(2);
- if (pcs == 7) return rec(6) + ids.at(1);
- if (pcs == 8) return rec(7) + ids.at(0);
- return rec(8);
- }
- 這個時候,我們會發現幾個有趣的數字,0 以及 8。他們用在了遞迴的參數,以及 ids 的 index 使用。
- 我們可以很快的觀察到 8 這個數字其實就是 ids 的長度,讓我們基於這個觀察再修改一下
- std::string unkonwn_logic_a(int pcs, std::string ids) {
- using namespace std::placeholders;
- const auto &rec = std::bind(unkonwn_logic_a, _1, ids);
- const auto &ids_len = ids.length();
- if (pcs <= 0) return "";
- if (pcs == 1) return rec(pcs - 1) + ids.at(ids_len - pcs);
- if (pcs == 2) return rec(pcs - 1) + ids.at(ids_len - pcs);
- if (pcs == 3) return rec(pcs - 1) + ids.at(ids_len - pcs);
- if (pcs == 4) return rec(pcs - 1) + ids.at(ids_len - pcs);
- if (pcs == 5) return rec(pcs - 1) + ids.at(ids_len - pcs);
- if (pcs == 6) return rec(pcs - 1) + ids.at(ids_len - pcs);
- if (pcs == 7) return rec(pcs - 1) + ids.at(ids_len - pcs);
- if (pcs == 8) return rec(pcs - 1) + ids.at(ids_len - pcs);
- return rec(8);
- }
- 哎呀,似乎發現了不得了的事情呢。這次,讓我們擺脫 8 的詛咒,使用 ids 的長度來處理他
- std::string unkonwn_logic_a(int pcs, std::string ids) {
- using namespace std::placeholders;
- const auto &rec = std::bind(unkonwn_logic_a, _1, ids);
- const auto &ids_len = ids.length();
- if (pcs <= 0) return "";
- if (pcs > ids_len) return rec(ids_len);
- return rec(pcs - 1) + ids.at(ids_len - pcs);
- }
- 遞迴... 遞迴... 遞... 迴... fold...
- 由於字串的相加具有結合律,(sa + sb) + sc = sa + (sb + sc),我們可以將原本的 right fold
- 改以 left fold 實作,剛好 std::accumulate 就是 left fold
- // 這個是小幫手.
- std::vector<int> range(int from, int to) {
- std::vector<int> ret{};
- for (int i = from; i <= to; i++) {
- ret.emplace_back(i);
- }
- return ret;
- }
- std::string unkonwn_logic_a(int pcs, std::string ids) {
- using namespace std::placeholders;
- const auto &rec = std::bind(unkonwn_logic_a, _1, ids);
- const auto &ids_len = ids.length();
- if (pcs <= 0) return "";
- if (pcs > ids_len) return rec(ids_len);
- const auto &pcs_range = range(1, pcs);
- return std::accumulate(pcs_range.cbegin(), pcs_range.cend(),
- std::string{},
- [&](std::string acc, int cur_pcs) {
- acc += ids.at(ids_len - cur_pcs);
- return std::move(acc);
- });
- }
- 最後,我們可以使用 for loop 去表達 left fold。不知道大家的 for loop 除了 left fold,還
- 用來表達了那些概念呢? 感覺會不小心搞不清楚是在 for 什麼呢
- std::string unkonwn_logic_a(int pcs, std::string ids) {
- using namespace std::placeholders;
- const auto &rec = std::bind(unkonwn_logic_a, _1, ids);
- const auto &ids_len = ids.length();
- if (pcs <= 0) return "";
- if (pcs > ids_len) return rec(ids_len);
- auto acc = std::string{};
- for (int cur_pcs = 1; cur_pcs <= pcs; cur_pcs++) {
- acc += ids.at(ids_len - cur_pcs);
- }
- return acc;
- }
- 可以針對 for loop 的特性做一些微調,讓程式碼更簡潔,以及修改一下型別,讓程式更明確
- std::string unkonwn_logic_a(size_t pcs, std::string ids) {
- const auto &ids_len = ids.length();
- pcs = std::min(pcs, ids_len);
- auto acc = std::string{};
- for (int cur_pcs = 1; cur_pcs <= pcs; cur_pcs++) {
- acc += ids.at(ids_len - cur_pcs);
- }
- return acc;
- }
- 好了,現在可以回答原 PO 的問題:想請教此程式如果想寫成迴圈該怎麼寫?
- 嗯,大概就是這樣
- 誒,等等,你說那些 bit operation 怎麽不見了,好吧,那讓我們處理處理。
- 首先,我們修改一下 unkonwn_logic_a 取得長度跟取 index 的形式,新增幾個小幫手
- std::string::size_type length(const std::string &s) { return s.length(); }
- std::string::value_type at(const std::string::size_type pos,
- const std::string &s) {
- return s.at(pos);
- }
- namespace std {
- std::string to_string(const std::string::value_type c) { return {c}; }
- } // namespace std
- std::string unkonwn_logic_a(size_t pcs, std::string ids) {
- const auto &ids_len = length(ids);
- pcs = std::min(pcs, ids_len);
- auto acc = std::string{};
- for (int cur_pcs = 1; cur_pcs <= pcs; cur_pcs++) {
- acc += std::to_string(at(ids_len - cur_pcs, ids));
- }
- return acc;
- }
- 接著把 unkonwn_logic_a 改為 template 的形式 (小祕密,函數實作根本一樣)。
- 這裡比較麻煩的是決定 pcs 的型別,詳細可以查查 decltype 跟 declval 的用法,這裡不贅述。
- template <typename IDS>
- std::string unkonwn_logic_a(decltype(length(std::declval<IDS>())) pcs,
- IDS &&ids) {
- const auto &ids_len = length(ids);
- pcs = std::min(pcs, ids_len);
- auto acc = std::string{};
- for (decltype(pcs) cur_pcs = 1; cur_pcs <= pcs; cur_pcs++) {
- acc += std::to_string(at(ids_len - cur_pcs, ids));
- }
- return acc;
- }
- 那假設我們想要用 uint8_t 去存 ids,就幫 uint8_t 實作 length, at 跟 std::to_string
- 就好了
- size_t length(const uint8_t &b) { return sizeof(b) * 8; }
- uint8_t at(const size_t pos, const uint8_t &b) {
- return (b & (1 << pos)) ? 1 : 0;
- }
- namespace std {
- std::string to_string(const uint8_t b) { return std::to_string((unsigned){b}); }
- } // namespace std
- 完成後,下面的程式碼就都可以運作了,在瀏覽器上跑跑看吧
- https://godbolt.org/z/wrd7Rv
- 這樣就優雅解決原 PO 的煩惱了:如果以後要讀更多ID我就無解了
- 對於通用的需求,我們可以使用 template 版本的 unkonwn_logic_a,只要幫存 id 的結構實作
- length, at 跟 std::to_string 就可以。而對於不喜歡 template 版本的人,也可以重新寫一份專
- 屬於特定型別的 unkonwn_logic_a,沒問題的。
- 最後一段那個 count 跟 label 的我實在看不懂,請讓我無視他。
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement