{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# C++ Test" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## valarray\n", "\n", "valarray 可以直接丟整進 cmath function 裡" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1, 1.41421, 1.73205, 2, 2.23607, " ] } ], "source": [ "#include \n", "#include \n", "#include \n", "\n", "std::valarray nums = {1, 2, 3, 4, 5};\n", "std::valarray sqrts = sqrt(nums);\n", "\n", "for(const double& num : sqrts)\n", " std::cout << num << \", \"; \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Range Enumeration 貌似不能用 Temporary Object\n", "\n", "下面這樣不行:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#include \n", "#include \n", "#include \n", "\n", "std::valarray nums = {1, 2, 3, 4, 5};\n", "\n", "for(const double& num : sqrt(nums))\n", " std::cout << num << \", \"; \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "cast 成 `valarray` 就可以:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1, 1.41421, 1.73205, 2, 2.23607, " ] } ], "source": [ "#include \n", "#include \n", "#include \n", "\n", "std::valarray nums = {1, 2, 3, 4, 5};\n", "\n", "for(const double& num : static_cast>(sqrt(nums)))\n", " std::cout << num << \", \"; \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [CppQuiz.org](https://cppquiz.org/quiz/question/225)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## py\n", "\n", "* structured binding\n", "* `std::max`(定義在 algorithm 裡)對三個數以上要這樣用 `std::max({1, 2, 3})`。直接寫 `std::max(1, 2, 3)` 的時候第三個 arg 是 comp\n", " * `std::max({1, 2, 3})` 可以用是因為有一個 constructor takes in initializer_list\n", " * 不能直接丟 container,例如 vector 給 `std::max`\n", " * 有 `std::max_element(v.begin(), v.end())` 回傳 iterator,要用 `*` 取值\n", "* python list append = c++ vector push_back\n", "* python `math.inf` = c++ `std::numeric_limits::infinity()`,定義在 ``\n", "* `deque` 比較" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `deque` 的 `pop_front()` 和 `pop_back()` 不回傳 element\n", "\n", "* [如果設計成回傳 element 會有兩個問題:](https://stackoverflow.com/questions/25035691/why-doesnt-stdqueuepop-return-value)\n", " * return element 會呼叫 copy ctor。如果 copy ctor 在 return 時 throw exception,該 element 也已經消失了\n", " * 對於不真正需要 popped element 的程序,return 時的 copy 是浪費時間" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template\n", "class queue {\n", " T* elements;\n", " std::size_t top_position;\n", " // stuff here\n", " T pop()\n", " {\n", " auto x = elements[top_position];\n", " // TODO: call destructor for elements[top_position] here\n", " --top_position; // alter queue state here\n", " return x; // calls T(const T&) which may throw\n", " }\n", "};" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ranges (C++ 20)\n", "\n", "* Functional programming in C++\n", "* [Cppcon presentation](https://youtu.be/FRkJCvHWdwQ?t=878)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "vector data {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};\n", "auto result { data\n", " | views::filter([](const auto& value) { return value % 2 == 0; })/* 2 4 6 8 10*/\n", " | views::transform([](const auto& value) { return value * 2.0; })/* 4 8 12 16 20 */\n", " | views::drop(2) /* 12 16 20 */\n", " | views::reverse /* 20 16 12 */\n", " | views::transform([](int i) { return to_string(i); }) /* \"20\" \"16\" \"12\" */\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comparator\n", "\n", "[這裡](http://fusharblog.com/3-ways-to-define-comparison-functions-in-cpp/)和[這裡](https://docs.oracle.com/cd/E19205-01/819-3701/com_5335.htm)都說 ```>=``` 不能當 comparator 因為會破壞 ```If f(x, y) then !f(y, x)``` (antisymmetry)。但測試起來沒問題啊???" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{ 9, 8, 8, 7, 6, 5, 4, 3, 3, 3, 2, 1 }" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#include \n", "#include \n", "\n", "std::vector a = {1, 2, 3, 3, 3, 4, 5, 6, 7, 8, 8, 9};\n", "\n", "std::sort(a.begin(), a.end(), [](int x, int y){ return x >=y; }); \n", "\n", "a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Raw String" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This is a \\n \"raw string\"\n" ] } ], "source": [ "#include \n", "\n", "std::cout << R\"(This is a \\n \"raw string\")\"<< std::endl;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ```std::greater``` and ```std::sort```\n", "\n", "* [3 Ways to Define Comparison Functions in C++](http://fusharblog.com/3-ways-to-define-comparison-functions-in-cpp/)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9, 8, 7, 6, 5, 4, 3, 2, 1, " ] } ], "source": [ "#include // std::cout\n", "#include // std::greater\n", "#include // std::sort\n", "#include \n", "\n", "int main () {\n", " std::vector a = {1, 2, 3, 4, 5, 6, 7, 8, 9};\n", " \n", " std::sort(a.begin(), a.end(), std::greater());\n", " \n", " for (const int& value : a)\n", " std::cout << value << \", \";\n", " \n", " return 0;\n", "}\n", "\n", "main();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ```std::to_string``` and ```std::stoi```" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{ 1, 2, 3 }" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#include \n", "#include // std::to_string and std::stoi\n", "#include \n", "\n", "int a = 123;\n", "\n", "std::vector v = {};\n", "for(char& c : std::to_string(a))\n", " v.push_back(std::stoi(std::string(1, c)));\n", "\n", "v" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Returning a Tuple" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1, 2\n" ] } ], "source": [ "#include \n", "#include \n", "\n", "std::tuple f(){ // cannot define as auto\n", " return {1, 2};\n", "}\n", "\n", "std::cout << std::get<0>(f()) << \", \" << std::get<1>(f()) << std::endl;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loop Over a Tuple? " ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1, 2, 3, 4, 5, " ] } ], "source": [ "#include \n", "\n", "for (auto x : {1, 2, 3, 4, 5})\n", " std::cout << x << \", \";" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## String Literal" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "baa\n" ] } ], "source": [ "#include \n", "#include \n", "\n", "{\n", "// const char* s = \"aaa\"; // 可以宣告但不能改內容。string literal 是存在 const 區\n", "// std::string s = \"aaa\"; // 可以宣告也可以改內容\n", "// char* s = \"aaa\"; // interpreter 不給過。因為 string literal 是 const 所以這樣宣告不合法\n", " char s[] = \"aaa\"; // 宣告成 array:可以宣告也可以改內容。其實這樣宣告\n", " \n", " s[0] = 'b';\n", " std::cout << s << std::endl;\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Random Practice Questions" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\" .stcejorp noissap fo muesum a si dlrow ehT\"" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// reverse a string\n", "\n", "#include \n", "\n", "std::string s = \"The world is a museum of passion projects. \";\n", "\n", "std::reverse(s.begin(), s.end());\n", "\n", "s" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\" .stcejorp noissap fo muesum a si dlrow ehT\"" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// reverse a string\n", "\n", "#include \n", "\n", "std::string reverse(std::string& s)\n", "{\n", " std::string res;\n", " res.resize(s.size());\n", " \n", " int j = s.size()-1;\n", " for (const char& c : s)\n", " res[j--] = c;\n", " \n", " return res;\n", "}\n", "\n", "std::string s = \"The world is a museum of passion projects. \";\n", "\n", "reverse(s)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n: 1\n", "p: 2\n", "f: 1\n", "j: 1\n", "u: 2\n", "t: 2\n", "h: 1\n", "e: 3\n", "r: 2\n", "s: 5\n", "w: 1\n", "o: 4\n", "l: 1\n", "d: 1\n", "i: 2\n", "c: 1\n", "a: 2\n", "m: 2\n" ] } ], "source": [ "// 算每個字母出現幾次,不分大小寫,忽略所有非英文字母字元\n", "\n", "#include \n", "#include \n", "#include \n", "#include \n", "#include \n", "\n", "std::string s = \"The world is a museum of passion projects. \";\n", "std::unordered_map count_map;\n", "\n", "int i = 0, j = s.size() - 1;\n", "while (i <= j) {\n", " if (!std::isalpha(s[i])) {\n", " std::swap(s[i], s[j]);\n", " j--;\n", " } else {\n", " s[i] = std::tolower(s[i]);\n", " i++;\n", " }\n", "}\n", "s.resize(j + 1);\n", "\n", "for (char c : s) {\n", " count_map[c]++;\n", "}\n", "\n", "std::for_each(count_map.begin(), count_map.end(), [](const std::pair& e){ std::cout << e.first << \": \" << e.second << std::endl; });" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n: 1\n", "p: 2\n", "f: 1\n", "j: 1\n", "u: 2\n", "t: 2\n", "h: 1\n", "e: 3\n", "r: 2\n", "s: 5\n", "w: 1\n", "o: 4\n", "l: 1\n", "d: 1\n", "i: 2\n", "c: 1\n", "a: 2\n", "m: 2\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\u001b[1minput_line_29:2:24: \u001b[0m\u001b[0;1;31merror: \u001b[0m\u001b[1muse of undeclared identifier 'lambda'\u001b[0m\n", " mime_bundle_repr(*(*((lambda)**)0x7ffcc058a128));\n", "\u001b[0;1;32m ^\n", "\u001b[0m\u001b[1minput_line_29:2:33: \u001b[0m\u001b[0;1;31merror: \u001b[0m\u001b[1mexpected expression\u001b[0m\n", " mime_bundle_repr(*(*((lambda)**)0x7ffcc058a128));\n", "\u001b[0;1;32m ^\n", "\u001b[0m" ] }, { "data": {}, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// 算每個字母出現幾次\n", "\n", "#include \n", "#include \n", "#include \n", "#include \n", "\n", "std::string s = \"The world is a museum of passion projects. \";\n", "std::unordered_map count_map;\n", "\n", "int i=0, j=s.size()-1;\n", "\n", "// 97 - 122: a-z\n", "// 65 - 90: A-Z\n", "\n", "while (i<=j){\n", " if (!((int)s[i] > 96 && (int)s[i] < 123)){\n", " if (!((int)s[i] > 64 && (int)s[i] < 91)){\n", " std::swap(s[i], s[j]);\n", " j--;\n", " } else {\n", " s[i] += 32;\n", " i++;\n", " }\n", " } else {\n", " i++;\n", " }\n", "}\n", "s.resize(j+1);\n", "\n", "for (const char& c : s)\n", "{\n", " if (count_map.find(c) == count_map.end()){ // not found\n", " count_map.insert({c, 1});\n", " } else {\n", " count_map[c] += 1;\n", " }\n", "}\n", "\n", "std::for_each(count_map.begin(), count_map.end(), [](const std::pair& e){ std::cout << e.first << \": \" << e.second << std::endl; }); // jupyter c++ kernel can't run structual binding in lambda" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{ 2, 3 }" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// 移除重複元素\n", "\n", "#include \n", "#include \n", "#include \n", "#include \n", "\n", "void unique(std::vector& a)\n", "{\n", " std::unordered_set unique_elements;\n", " int i = 0, j = a.size()-1;\n", " while (i <= j){\n", " if (unique_elements.find(a[i]) == unique_elements.end()){ // not found\n", " unique_elements.insert(a[i]);\n", " i++;\n", " } else {\n", " std::swap(a[i], a[j]);\n", " j--;\n", " }\n", " }\n", " a.resize(i);\n", "}\n", "\n", "std::vector a = {2, 2, 3}; \n", "\n", "unique(a);\n", "\n", "a" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "120" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// 階乘\n", "\n", "int factorial(int n)\n", "{\n", " if (n<2) {\n", " return 1; \n", " } else {\n", " return n*factorial(n-1);\n", " }\n", "}\n", "\n", "factorial(5)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "false" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// 判斷是否潤年\n", "\n", "bool is_leap_year(int year){\n", " return ((year%4==0) && (year%100!=0)) || (year%400==0);\n", "}\n", "\n", "is_leap_year(1900)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{ 8, 0 }" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// 找最大值,最小值\n", "\n", "#include \n", "#include \n", "#include \n", "\n", "std::vector integers = {0, 5, 2, 6, 3, 1, 5, 7, 8};\n", "int max = -std::numeric_limits::infinity();\n", "int min = std::numeric_limits::infinity();\n", "\n", "for(int i : integers){\n", " max = (i > max) ? i : max;\n", " min = (i < min) ? i : min;\n", "}\n", " \n", "std::vector({max, min})" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{ 8, 0 }" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// 找最大值,最小值\n", "\n", "#include \n", "#include \n", "#include \n", "\n", "std::vector v = {0, 5, 2, 6, 3, 1, 5, 7, 8};\n", " \n", "std::vector({*std::max_element(v.begin(), v.end()), *std::min_element(v.begin(), v.end())})" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "false" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// 判斷是否質數\n", "\n", "#include \n", "\n", "bool is_prime(int n)\n", "{\n", " if (n==1)\n", " return false;\n", " for (int i=2 ; i\n", "#include \n", "#include \n", "\n", "std::vector> a = {{0, 9}, {5, 4}, {2, 7}, {6, 3}, {3, 6}, {1, 8}, {5, 4}, {7, 2}, {8, 1}};\n", "\n", "std::sort(a.begin(), a.end(), [](const std::pair& a, const std::pair& b){ return a.first < b.first; });\n", "\n", "a" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// 算有幾個偶數\n", "\n", "#include \n", "#include \n", "\n", "std::vector v = {0, 5, 2, 6, 3, 1, 5, 7, 8, 9, 4, 7, 3, 6, 8, 4, 2, 1};\n", "\n", "std::count_if(v.begin(), v.end(), [](const int& n){ return n%2==0; })" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a: 2\n", "e: 1\n", "i: 2\n", "n: 1\n", "q: 1\n", "t: 3\n", "u: 1\n", "v: 1\n" ] } ], "source": [ "// 照字母順序排序並計算出現次數\n", "\n", "#include \n", "#include \n", "#include \n", "#include \n", "#include \n", "\n", "std::string s = \"quantitative\";\n", "std::sort(s.begin(), s.end());\n", "\n", "std::map count;\n", "\n", "for (const char& c : s)\n", " count[c]++;\n", "\n", "std::for_each(count.begin(), count.end(), [](const std::pair& item){ std::cout << item.first << \": \" << item.second << std::endl; } );" ] } ], "metadata": { "kernelspec": { "display_name": "C++17", "language": "C++17", "name": "xcpp17" }, "language_info": { "codemirror_mode": "text/x-c++src", "file_extension": ".cpp", "mimetype": "text/x-c++src", "name": "c++", "version": "17" } }, "nbformat": 4, "nbformat_minor": 4 }