Advertisement
Guest User

Untitled

a guest
Mar 31st, 2020
521
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.97 KB | None | 0 0
  1. - 因為不知道 AnsiString 是什麼,這裡我先使用 std::string 代替,還請見諒
  2. - 示範部分,單純為了方面看到內容,存入了 1 跟 0 以外的數值,一切以原 PO 的規格為主
  3. id 順序的部分啊,我就使用遞增去作了
  4.  
  5. 首先,我們來看看這段邏輯
  6.  
  7. if(pcs==1)ID_display=bit7;
  8. if(pcs==2)ID_display=bit7+bit6;
  9. if(pcs==3)ID_display=bit7+bit6+bit5;
  10. if(pcs==4)ID_display=bit7+bit6+bit5+bit4;
  11. if(pcs==5)ID_display=bit7+bit6+bit5+bit4+bit3;
  12. if(pcs==6)ID_display=bit7+bit6+bit5+bit4+bit3+bit2;
  13. if(pcs==7)ID_display=bit7+bit6+bit5+bit4+bit3+bit2+bit1; //最多7個
  14.  
  15. 讓我們先把他變成一個函數
  16.  
  17. std::string unkonwn_logic_a(int pcs, std::string bit0, std::string bit1,
  18. std::string bit2, std::string bit3,
  19. std::string bit4, std::string bit5,
  20. std::string bit6, std::string bit7) {
  21. if (pcs == 1) return bit7;
  22. if (pcs == 2) return bit7 + bit6;
  23. if (pcs == 3) return bit7 + bit6 + bit5;
  24. if (pcs == 4) return bit7 + bit6 + bit5 + bit4;
  25. if (pcs == 5) return bit7 + bit6 + bit5 + bit4 + bit3;
  26. if (pcs == 6) return bit7 + bit6 + bit5 + bit4 + bit3 + bit2;
  27. if (pcs == 7) return bit7 + bit6 + bit5 + bit4 + bit3 + bit2 + bit1;
  28. }
  29.  
  30. 可以觀察到,事情似乎有些有趣。來改寫一下
  31.  
  32. std::string unkonwn_logic_a(int pcs, std::string bit0, std::string bit1,
  33. std::string bit2, std::string bit3,
  34. std::string bit4, std::string bit5,
  35. std::string bit6, std::string bit7) {
  36.  
  37. using namespace std::placeholders;
  38.  
  39. const auto &rec = std::bind(unkonwn_logic_a, _1, bit0, bit1, bit2, bit3, bit4,
  40. bit5, bit6, bit7);
  41.  
  42. // TODO pcs 小於等於 0 該做些什麼?
  43.  
  44. if (pcs == 1) return bit7;
  45. if (pcs == 2) return rec(1) + bit6;
  46. if (pcs == 3) return rec(2) + bit5;
  47. if (pcs == 4) return rec(3) + bit4;
  48. if (pcs == 5) return rec(4) + bit3;
  49. if (pcs == 6) return rec(5) + bit2;
  50. if (pcs == 7) return rec(6) + bit1;
  51.  
  52. // TODO pcs 大於 7 該做些什麼?
  53. }
  54.  
  55. 由於是遞迴結構,我們觀察前面兩個看看
  56.  
  57. // 當 pcs 為 1 時,我們取尾巴 1 個
  58. if (pcs == 1) return bit7;
  59.  
  60. // 當 pcs 為 2 時,我們取尾巴 2 個
  61. if (pcs == 2) return rec(1) + bit6;
  62.  
  63. 因此我們可以 "合理" 推斷,當 pcs 為 n 時,我們取尾巴 n 個,這樣就完成剛剛的 TODO 了
  64. (當然,合理因人而異,這裡只是提供一種可能性而已,畢竟原 PO 並沒有提供其他的線索)
  65.  
  66. std::string unkonwn_logic_a(int pcs, std::string bit0, std::string bit1,
  67. std::string bit2, std::string bit3,
  68. std::string bit4, std::string bit5,
  69. std::string bit6, std::string bit7) {
  70.  
  71. using namespace std::placeholders;
  72.  
  73. const auto &rec = std::bind(unkonwn_logic_a, _1, bit0, bit1, bit2, bit3, bit4,
  74. bit5, bit6, bit7);
  75.  
  76. if (pcs <= 0) return "";
  77. if (pcs == 1) return rec(0) + bit7;
  78. if (pcs == 2) return rec(1) + bit6;
  79. if (pcs == 3) return rec(2) + bit5;
  80. if (pcs == 4) return rec(3) + bit4;
  81. if (pcs == 5) return rec(4) + bit3;
  82. if (pcs == 6) return rec(5) + bit2;
  83. if (pcs == 7) return rec(6) + bit1;
  84. if (pcs == 8) return rec(7) + bit0;
  85.  
  86. return rec(8);
  87. }
  88.  
  89. Ok,現在我們來處理應該要是 ID 但是名字卻是 bit 的變數們,讓我們稍微改變一下寫法
  90.  
  91. std::string unkonwn_logic_a(int pcs, std::string ids) {
  92.  
  93. using namespace std::placeholders;
  94.  
  95. const auto &rec = std::bind(unkonwn_logic_a, _1, ids);
  96.  
  97. if (pcs <= 0) return "";
  98. if (pcs == 1) return rec(0) + ids.at(7);
  99. if (pcs == 2) return rec(1) + ids.at(6);
  100. if (pcs == 3) return rec(2) + ids.at(5);
  101. if (pcs == 4) return rec(3) + ids.at(4);
  102. if (pcs == 5) return rec(4) + ids.at(3);
  103. if (pcs == 6) return rec(5) + ids.at(2);
  104. if (pcs == 7) return rec(6) + ids.at(1);
  105. if (pcs == 8) return rec(7) + ids.at(0);
  106.  
  107. return rec(8);
  108. }
  109.  
  110. 這個時候,我們會發現幾個有趣的數字,0 以及 8。他們用在了遞迴的參數,以及 ids 的 index 使用。
  111. 我們可以很快的觀察到 8 這個數字其實就是 ids 的長度,讓我們基於這個觀察再修改一下
  112.  
  113. std::string unkonwn_logic_a(int pcs, std::string ids) {
  114.  
  115. using namespace std::placeholders;
  116.  
  117. const auto &rec = std::bind(unkonwn_logic_a, _1, ids);
  118. const auto &ids_len = ids.length();
  119.  
  120. if (pcs <= 0) return "";
  121. if (pcs == 1) return rec(pcs - 1) + ids.at(ids_len - pcs);
  122. if (pcs == 2) return rec(pcs - 1) + ids.at(ids_len - pcs);
  123. if (pcs == 3) return rec(pcs - 1) + ids.at(ids_len - pcs);
  124. if (pcs == 4) return rec(pcs - 1) + ids.at(ids_len - pcs);
  125. if (pcs == 5) return rec(pcs - 1) + ids.at(ids_len - pcs);
  126. if (pcs == 6) return rec(pcs - 1) + ids.at(ids_len - pcs);
  127. if (pcs == 7) return rec(pcs - 1) + ids.at(ids_len - pcs);
  128. if (pcs == 8) return rec(pcs - 1) + ids.at(ids_len - pcs);
  129.  
  130. return rec(8);
  131. }
  132.  
  133. 哎呀,似乎發現了不得了的事情呢。這次,讓我們擺脫 8 的詛咒,使用 ids 的長度來處理他
  134.  
  135. std::string unkonwn_logic_a(int pcs, std::string ids) {
  136.  
  137. using namespace std::placeholders;
  138.  
  139. const auto &rec = std::bind(unkonwn_logic_a, _1, ids);
  140. const auto &ids_len = ids.length();
  141.  
  142. if (pcs <= 0) return "";
  143. if (pcs > ids_len) return rec(ids_len);
  144.  
  145. return rec(pcs - 1) + ids.at(ids_len - pcs);
  146. }
  147.  
  148. 遞迴... 遞迴... 遞... 迴... fold...
  149. 由於字串的相加具有結合律,(sa + sb) + sc = sa + (sb + sc),我們可以將原本的 right fold
  150. 改以 left fold 實作,剛好 std::accumulate 就是 left fold
  151.  
  152. // 這個是小幫手.
  153. std::vector<int> range(int from, int to) {
  154. std::vector<int> ret{};
  155. for (int i = from; i <= to; i++) {
  156. ret.emplace_back(i);
  157. }
  158. return ret;
  159. }
  160.  
  161. std::string unkonwn_logic_a(int pcs, std::string ids) {
  162.  
  163. using namespace std::placeholders;
  164.  
  165. const auto &rec = std::bind(unkonwn_logic_a, _1, ids);
  166. const auto &ids_len = ids.length();
  167.  
  168. if (pcs <= 0) return "";
  169. if (pcs > ids_len) return rec(ids_len);
  170.  
  171. const auto &pcs_range = range(1, pcs);
  172.  
  173. return std::accumulate(pcs_range.cbegin(), pcs_range.cend(),
  174. std::string{},
  175. [&](std::string acc, int cur_pcs) {
  176. acc += ids.at(ids_len - cur_pcs);
  177. return std::move(acc);
  178. });
  179. }
  180.  
  181. 最後,我們可以使用 for loop 去表達 left fold。不知道大家的 for loop 除了 left fold,還
  182. 用來表達了那些概念呢? 感覺會不小心搞不清楚是在 for 什麼呢
  183.  
  184. std::string unkonwn_logic_a(int pcs, std::string ids) {
  185.  
  186. using namespace std::placeholders;
  187.  
  188. const auto &rec = std::bind(unkonwn_logic_a, _1, ids);
  189. const auto &ids_len = ids.length();
  190.  
  191. if (pcs <= 0) return "";
  192. if (pcs > ids_len) return rec(ids_len);
  193.  
  194. auto acc = std::string{};
  195. for (int cur_pcs = 1; cur_pcs <= pcs; cur_pcs++) {
  196. acc += ids.at(ids_len - cur_pcs);
  197. }
  198. return acc;
  199. }
  200.  
  201. 可以針對 for loop 的特性做一些微調,讓程式碼更簡潔,以及修改一下型別,讓程式更明確
  202.  
  203. std::string unkonwn_logic_a(size_t pcs, std::string ids) {
  204. const auto &ids_len = ids.length();
  205.  
  206. pcs = std::min(pcs, ids_len);
  207.  
  208. auto acc = std::string{};
  209. for (int cur_pcs = 1; cur_pcs <= pcs; cur_pcs++) {
  210. acc += ids.at(ids_len - cur_pcs);
  211. }
  212. return acc;
  213. }
  214.  
  215. 好了,現在可以回答原 PO 的問題:想請教此程式如果想寫成迴圈該怎麼寫?
  216. 嗯,大概就是這樣
  217.  
  218. 誒,等等,你說那些 bit operation 怎麽不見了,好吧,那讓我們處理處理。
  219.  
  220. 首先,我們修改一下 unkonwn_logic_a 取得長度跟取 index 的形式,新增幾個小幫手
  221.  
  222. std::string::size_type length(const std::string &s) { return s.length(); }
  223.  
  224. std::string::value_type at(const std::string::size_type pos,
  225. const std::string &s) {
  226. return s.at(pos);
  227. }
  228.  
  229. namespace std {
  230.  
  231. std::string to_string(const std::string::value_type c) { return {c}; }
  232.  
  233. } // namespace std
  234.  
  235. std::string unkonwn_logic_a(size_t pcs, std::string ids) {
  236. const auto &ids_len = length(ids);
  237.  
  238. pcs = std::min(pcs, ids_len);
  239.  
  240. auto acc = std::string{};
  241. for (int cur_pcs = 1; cur_pcs <= pcs; cur_pcs++) {
  242. acc += std::to_string(at(ids_len - cur_pcs, ids));
  243. }
  244. return acc;
  245. }
  246.  
  247. 接著把 unkonwn_logic_a 改為 template 的形式 (小祕密,函數實作根本一樣)。
  248. 這裡比較麻煩的是決定 pcs 的型別,詳細可以查查 decltype 跟 declval 的用法,這裡不贅述。
  249.  
  250. template <typename IDS>
  251. std::string unkonwn_logic_a(decltype(length(std::declval<IDS>())) pcs,
  252. IDS &&ids) {
  253. const auto &ids_len = length(ids);
  254.  
  255. pcs = std::min(pcs, ids_len);
  256.  
  257. auto acc = std::string{};
  258. for (decltype(pcs) cur_pcs = 1; cur_pcs <= pcs; cur_pcs++) {
  259. acc += std::to_string(at(ids_len - cur_pcs, ids));
  260. }
  261. return acc;
  262. }
  263.  
  264. 那假設我們想要用 uint8_t 去存 ids,就幫 uint8_t 實作 length, at 跟 std::to_string
  265. 就好了
  266.  
  267. size_t length(const uint8_t &b) { return sizeof(b) * 8; }
  268.  
  269. uint8_t at(const size_t pos, const uint8_t &b) {
  270. return (b & (1 << pos)) ? 1 : 0;
  271. }
  272.  
  273. namespace std {
  274.  
  275. std::string to_string(const uint8_t b) { return std::to_string((unsigned){b}); }
  276.  
  277. } // namespace std
  278.  
  279. 完成後,下面的程式碼就都可以運作了,在瀏覽器上跑跑看吧
  280.  
  281. https://godbolt.org/z/wrd7Rv
  282.  
  283. 這樣就優雅解決原 PO 的煩惱了:如果以後要讀更多ID我就無解了
  284.  
  285. 對於通用的需求,我們可以使用 template 版本的 unkonwn_logic_a,只要幫存 id 的結構實作
  286. length, at 跟 std::to_string 就可以。而對於不喜歡 template 版本的人,也可以重新寫一份專
  287. 屬於特定型別的 unkonwn_logic_a,沒問題的。
  288.  
  289. 最後一段那個 count 跟 label 的我實在看不懂,請讓我無視他。
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement