diff --git a/notebooks/07_STL_Set+Map+Algorithms.ipynb b/notebooks/07_STL_Set+Map+Algorithms.ipynb index 1de53db632957153496c8406c757ac5c773284cd..2618e9618bbedada18c4c00d582462b30e94a19a 100644 --- a/notebooks/07_STL_Set+Map+Algorithms.ipynb +++ b/notebooks/07_STL_Set+Map+Algorithms.ipynb @@ -1 +1,887 @@ -{"metadata":{"orig_nbformat":4,"kernelspec":{"display_name":"C++14","language":"C++14","name":"xcpp14"},"language_info":{"codemirror_mode":"text/x-c++src","file_extension":".cpp","mimetype":"text/x-c++src","name":"c++","version":"14"}},"nbformat_minor":5,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# STL - Part 2 : More Containers & Algorithms","metadata":{},"id":"bac1d62f"},{"cell_type":"markdown","source":"#### Sets","metadata":{},"id":"efdc5616"},{"cell_type":"code","source":"#include <iostream>\n#include <set>\n\nstd::set< int > s = {1, 7, 4, 8, 2}; // create a set container and fill it\n\ns.insert(5); // insert another element\ns.insert(4);\n\n// check how often an element is inside the set\nfor ( int i = 0; i < 8; ++i ) {\n std::cout << i << \" appears \" << s.count( i ) << \" times\\n\";\n}","metadata":{"trusted":true},"execution_count":2,"outputs":[{"name":"stdout","text":"0 appears 0 times\n1 appears 1 times\n2 appears 1 times\n3 appears 0 times\n4 appears 1 times\n5 appears 1 times\n6 appears 0 times\n7 appears 1 times\n","output_type":"stream"}],"id":"c2848a05"},{"cell_type":"markdown","source":"**Remarks:**\n- Although we inserted **4** twice, it is only stored once in the set data structure. Just like a mathematical set a ```std::set``` can contain a specific object only once.\n- Hence, ```count()``` will always return either 0 or 1.\n- This shows that ```std::set``` is no sequence container.\n- Instead it stores its elements in a **sorted** fashion. This guarantees logarithmic complexity for element access.","metadata":{},"id":"44573775"},{"cell_type":"markdown","source":"Of course we can store various kinds of objects in a set ...","metadata":{},"id":"a415d236"},{"cell_type":"code","source":"struct myPair {\n myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {};\n int fir_;\n int sec_;\n};\n\nstd::set< myPair > pairs; ","metadata":{"trusted":true},"execution_count":3,"outputs":[],"id":"2213e98e"},{"cell_type":"markdown","source":"... but there is a caveat. Check what happens, when we try to insert an object of type ```myPair``` into the set:","metadata":{},"id":"725387bc"},{"cell_type":"code","source":"pairs.insert( myPair(1,2) );","metadata":{"trusted":true},"execution_count":4,"outputs":[{"name":"stderr","text":"In file included from input_line_5:1:\nIn file included from /srv/conda/envs/notebook/include/xeus/xinterpreter.hpp:13:\nIn file included from /srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/functional:49:\n/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_function.h:386:20: error: invalid operands to binary expression ('const __cling_N54::myPair' and 'const __cling_N54::myPair')\n { return __x < __y; }\n ~~~ ^ ~~~\n/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_tree.h:2100:13: note: in instantiation of member function 'std::less<__cling_N54::myPair>::operator()' requested here\n __comp = _M_impl._M_key_compare(__k, _S_key(__x));\n ^\n/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_tree.h:2153:4: note: in instantiation of member function 'std::_Rb_tree<__cling_N54::myPair, __cling_N54::myPair, std::_Identity<__cling_N54::myPair>, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::_M_get_insert_unique_pos' requested here\n = _M_get_insert_unique_pos(_KeyOfValue()(__v));\n ^\n/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_set.h:521:9: note: in instantiation of function template specialization 'std::_Rb_tree<__cling_N54::myPair, __cling_N54::myPair, std::_Identity<__cling_N54::myPair>, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::_M_insert_unique<__cling_N54::myPair>' requested here\n _M_t._M_insert_unique(std::move(__x));\n ^\ninput_line_12:2:8: note: in instantiation of member function 'std::set<__cling_N54::myPair, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::insert' requested here\n pairs.insert( myPair(1,2) );\n ^\nIn file included from input_line_5:1:\nIn file included from /srv/conda/envs/notebook/include/xeus/xinterpreter.hpp:17:\nIn file included from /srv/conda/envs/notebook/include/xeus/xcomm.hpp:15:\nIn file included from /srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/map:60:\n/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_tree.h:777:2: error: static_assert failed \"comparison object must be invocable with two arguments of key type\"\n static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{},\n ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_tree.h:2100:41: note: in instantiation of member function 'std::_Rb_tree<__cling_N54::myPair, __cling_N54::myPair, std::_Identity<__cling_N54::myPair>, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::_S_key' requested here\n __comp = _M_impl._M_key_compare(__k, _S_key(__x));\n ^\n/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_tree.h:2153:4: note: in instantiation of member function 'std::_Rb_tree<__cling_N54::myPair, __cling_N54::myPair, std::_Identity<__cling_N54::myPair>, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::_M_get_insert_unique_pos' requested here\n = _M_get_insert_unique_pos(_KeyOfValue()(__v));\n ^\n/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_set.h:521:9: note: in instantiation of function template specialization 'std::_Rb_tree<__cling_N54::myPair, __cling_N54::myPair, std::_Identity<__cling_N54::myPair>, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::_M_insert_unique<__cling_N54::myPair>' requested here\n _M_t._M_insert_unique(std::move(__x));\n ^\ninput_line_12:2:8: note: in instantiation of member function 'std::set<__cling_N54::myPair, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::insert' requested here\n pairs.insert( myPair(1,2) );\n ^\n","output_type":"stream"},{"ename":"Interpreter Error","evalue":"","traceback":["Interpreter Error: "],"output_type":"error"}],"id":"51fd5597"},{"cell_type":"markdown","source":"**What went wrong?**\n\nAs the set stores its elements in a **sorted** fashion it needs some way to **order** them.\nBy default the standard ```<``` relation is used.\n\nThat does not work for our ```myPair``` data type.\n\nWe need to define our own comparison operator for the class.\n\nThere are plenty ways of doing that. Below we will use a free function for it.","metadata":{},"id":"2ee8f731"},{"cell_type":"code","source":"%%file demo.cpp\n\n#include <iostream>\n#include <set>\n\nstruct myPair {\n myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {};\n int fir_;\n int sec_;\n};\n\n// our comparison function will return true, if the sum of the squares\n// of the values in left is smaller than that in right (problem with tie-breaking?)\nbool cmp( const myPair& left, const myPair& right ) {\n int val1 = left.fir_ * left.fir_ + left.sec_ * left.sec_;\n int val2 = right.fir_ * right.fir_ + right.sec_ * right.sec_;\n return val1 < val2;\n}\n\nint main() {\n \n // create two objects\n myPair p1( 1, 2 );\n myPair p2( 3, 4 );\n\n // compare them\n std::cout << \"p1 < p2 is \" << cmp( p1, p2 ) << std::endl;\n std::cout << \"p2 < p1 is \" << cmp( p2, p1 ) << std::endl;\n\n // a free function in C/C++ is represented by the address of its machine code in memory;\n // thus, the type of argument is a function pointer;\n // we need to pass that info as a second template argument;\n // decltype returns the type of an expression\n std::set< myPair, decltype( cmp )* > pairs( cmp );\n\n // alternatively we could do it ourselves; note that the (*) is important!\n // but that way is not very C++-ish\n // std::set< myPair, bool (*)( const myPair&, const myPair& ) > pairs( cmp );\n \n // now insertion will work\n pairs.insert( p1 );\n pairs.insert( p2 );\n\n std::cout << \"insertion successful\" << std::endl;\n}","metadata":{"trusted":true},"execution_count":5,"outputs":[{"name":"stdout","text":"Writing demo.cpp\n","output_type":"stream"}],"id":"e8c29594"},{"cell_type":"code","source":"!g++ demo.cpp","metadata":{"trusted":true},"execution_count":6,"outputs":[],"id":"0a0207dd"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":7,"outputs":[{"name":"stdout","text":"p1 < p2 is 1\np2 < p1 is 0\ninsertion successful\n","output_type":"stream"}],"id":"68e1df4b"},{"cell_type":"markdown","source":"**Note:** \nThe STL offers a variant **```std::unordered_set```** that stores its elements in an unsorted fashion. However, that would not solve our problem. Instead of a **comparison** we then would need to implement a **hashing function**.","metadata":{},"id":"f8b3109b"},{"cell_type":"markdown","source":"***\nThe way we added the new element in the example, i.e. via\n\n```pairs.insert( myPair(1,2) );```\n\nagain induced a copy operation. As with ```vector``` and ```list``` we could use ```emplace()``` instead.\n\nFor demonstration purposes we make the constructor of ```myPair``` verbose.","metadata":{},"id":"59ab93ca"},{"cell_type":"code","source":"%%file demo.cpp\n\n#include <iostream>\n#include <set>\n\nstruct myPair {\n myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {\n std::cout << \"(\" << fir_ << \",\" << sec_ << \") constructed\" << std::endl;\n };\n \n int fir_;\n int sec_;\n};\n\n// our comparison function: will return true, if the square of the values\n// in left is smaller than that in right\nbool cmp( const myPair& left, const myPair& right ) {\n int val1 = left.fir_ * left.fir_ + left.sec_ * left.sec_;\n int val2 = right.fir_ * right.fir_ + right.sec_ * right.sec_;\n return val1 < val2;\n}\n\nint main() {\n \n std::set< myPair, decltype( cmp )* > pairs( cmp );\n\n pairs.emplace( 1, 2 );\n pairs.emplace( 3, 4 );\n pairs.emplace( 1, 2 );\n}","metadata":{"trusted":true},"execution_count":8,"outputs":[{"name":"stdout","text":"Overwriting demo.cpp\n","output_type":"stream"}],"id":"bdda6c33"},{"cell_type":"code","source":"!g++ demo.cpp","metadata":{"trusted":true},"execution_count":9,"outputs":[],"id":"8099d1a4"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":11,"outputs":[{"name":"stdout","text":"(1,2) constructed\n(3,4) constructed\n(1,2) constructed\n","output_type":"stream"}],"id":"5d491b27"},{"cell_type":"markdown","source":"#### Associative Containers\n\nQuoting Wikipedia:\n\n> In computer science, an **associative array**, **map**, **symbol table**, or **dictionary** is an abstract data type composed of a collection of **(key, value) pairs**, such that each possible key appears at most once in the collection.\n>\n> Operations associated with this data type allow to:\n>\n>- add a pair to the collection;\n>- remove a pair from the collection;\n>- modify an existing pair;\n>- lookup a value associated with a particular key.\n\nThe STL also offers associative containers. An example is ```std::map```.","metadata":{},"id":"8e256275"},{"cell_type":"markdown","source":"Return to our example with the traffic light. Assume that we want to print the currect state of a specific traffic light. How to do that?\n\nWell, using an enumeration for the state we can use the classical switch-case-construct:","metadata":{},"id":"fb3ef7bb"},{"cell_type":"code","source":"%%file ampel.cpp\n\n#include <iostream>\n\ntypedef enum{ GREEN, YELLOW, RED, YELLOW_RED } trafficLight;\n\nvoid ampel( trafficLight tf ) {\n\n switch( tf ) {\n case GREEN:\n std::cout << \"Lights are green\" << std::endl;\n break;\n case YELLOW:\n std::cout << \"Lights are yellow\" << std::endl;\n break;\n case RED:\n std::cout << \"Lights are red\" << std::endl;\n break;\n case YELLOW_RED:\n std::cout << \"Lights are yellow-red\" << std::endl;\n break;\n }\n\n}\n\nint main() {\n trafficLight tf = GREEN;\n ampel( tf );\n}","metadata":{"trusted":true},"execution_count":12,"outputs":[{"name":"stdout","text":"Writing ampel.cpp\n","output_type":"stream"}],"id":"59839aea"},{"cell_type":"code","source":"!g++ ampel.cpp","metadata":{"trusted":true},"execution_count":13,"outputs":[],"id":"76c8886d"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":14,"outputs":[{"name":"stdout","text":"Lights are green\n","output_type":"stream"}],"id":"731e7c94"},{"cell_type":"markdown","source":"Another (neater) way is to associate the state with a corresponding string","metadata":{},"id":"08b68b2b"},{"cell_type":"code","source":"%%file ampel.cpp\n\n#include <iostream>\n#include <map>\n\ntypedef enum{ GREEN, YELLOW, RED, YELLOW_RED } trafficLight;\n\nint main() {\n\n std::map< trafficLight, std::string > tf2str =\n { { GREEN, \"green\" }, { YELLOW, \"yellow\" }, { RED, \"red\" },\n { YELLOW_RED, \"yellow-red\" } };\n\n trafficLight tf = GREEN;\n\n std::cout << \"Lights are \" << tf2str[ tf ] << std::endl;\n}","metadata":{"trusted":true},"execution_count":15,"outputs":[{"name":"stdout","text":"Overwriting ampel.cpp\n","output_type":"stream"}],"id":"8fe484bf"},{"cell_type":"code","source":"!g++ ampel.cpp","metadata":{"trusted":true},"execution_count":16,"outputs":[],"id":"74251bd8"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":17,"outputs":[{"name":"stdout","text":"Lights are green\n","output_type":"stream"}],"id":"5b919ca3"},{"cell_type":"markdown","source":"Another example, demonstrating additional features of ```std::map``` (converted from Gottschling, *Forschung mit modernem C++*)","metadata":{},"id":"b1718cdd"},{"cell_type":"code","source":"%%file constants.cpp\n\n#include <iostream>\n#include <string>\n#include <map>\n#include <cmath>\n\nint main() {\n\n // create a map and fill it with some (key,value) pairs\n std::map< std::string, double > constants = { {\"e\", std::exp(1.0)},\n {\"pi\", 4.0*std::atan(1.0) }, {\"h\", 6.6e-34} };\n\n // subscript operator is overloaded to allow access via a key\n std::cout << \"Value of Planck constant is \" << constants[ \"h\" ] << '\\n';\n constants[ \"c\" ] = 299792458;\n\n // Hmmm, what happens here? No key \"k\" exists so far!\n std::cout << \"Value of Coulomb constant is \" << constants[ \"k\" ] << '\\n';\n\n // find() allows to check for existance of a key; returns an iterator\n // to the pair, if it is found\n std::cout << \"Value of pi is \" << constants.find( \"pi\" )->second << '\\n';\n\n // if not it returns end\n auto it_phi = constants.find( \"phi\" );\n if ( it_phi != constants.end() ) {\n std::cout << \"The golden ratio is \" << it_phi->second << '\\n';\n }\n\n // can use at(), if we know the pair to exists, returns value for key\n // will throw an \"out_of_range\" exception, if we were wrong\n std::cout << \"Value of Euler constant is \" << constants.at( \"e\" ) << \"\\n\\n\";\n\n // range-based loop\n for ( auto& c: constants ) {\n std::cout << \"Value of \" << c.first << \" is \" << c.second << '\\n';\n }\n}","metadata":{"trusted":true},"execution_count":24,"outputs":[{"name":"stdout","text":"Overwriting constants.cpp\n","output_type":"stream"}],"id":"52f631d4"},{"cell_type":"code","source":"!g++ constants.cpp","metadata":{"trusted":true},"execution_count":25,"outputs":[],"id":"aaba61ba"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":26,"outputs":[{"name":"stdout","text":"Value of Planck constant is 6.6e-34\nValue of Coulomb constant is 0\nValue of pi is 3.14159\nValue of Euler constant is 2.71828\n\nValue of c is 2.99792e+08\nValue of e is 2.71828\nValue of h is 6.6e-34\nValue of k is 0\nValue of pi is 3.14159\n","output_type":"stream"}],"id":"3f9362c9"},{"cell_type":"markdown","source":"**Note:** \nAs with ```set``` there is also a variant of ```map``` that uses hashing instead of ordered storage and is called ```unordered_map```.","metadata":{},"id":"a7e8490c"},{"cell_type":"markdown","source":"#### Algorithm\n\nThe STL supports also various algorithms that work on the entries in a container. The advantage again is that these save us implementation and will (potentially) work for various kinds of containers.\n\nWe will briefly look at two examples.","metadata":{},"id":"2032e7f2"},{"cell_type":"markdown","source":"**Example 1:** Remove double entries from a sequence","metadata":{},"id":"4c239bfa"},{"cell_type":"code","source":"%%file uniq.cpp\n\n#include <algorithm>\n#include <vector>\n#include <iostream>\n\nusing Container = std::vector<int>;\n\nvoid print( const Container& box, const std::string& note ) {\n std::cout << \"( \";\n for( int w: box ) std::cout << w << ' ';\n std::cout << \") \" << note << std::endl;\n}\n \nint main() {\n\n Container box{ 3, 5, 2, 4, 1, 2, 1 };\n print( box, \"<- unsorted\" );\n\n sort( box.begin(), box.end() );\n print( box, \"<- sorted\" );\n\n Container::iterator last = unique( begin(box), end(box) );\n print( box, \"<- happened in-place\" );\n\n box.resize( distance( box.begin(), last ) );\n print( box, \" <- truncated to new length\" );\n}","metadata":{"trusted":true},"execution_count":27,"outputs":[{"name":"stdout","text":"Writing uniq.cpp\n","output_type":"stream"}],"id":"aed454ce"},{"cell_type":"code","source":"!g++ uniq.cpp","metadata":{"trusted":true},"execution_count":28,"outputs":[],"id":"57c92377"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":29,"outputs":[{"name":"stdout","text":"( 3 5 2 4 1 2 1 ) <- unsorted\n( 1 1 2 2 3 4 5 ) <- sorted\n( 1 2 3 4 5 4 5 ) <- happened in-place\n( 1 2 3 4 5 ) <- truncated to new length\n","output_type":"stream"}],"id":"b190c1c6"},{"cell_type":"markdown","source":"**Note:**\n\nReplacing ```vector``` by ```list``` via\n\n using Container = std::list<int>;\n\nwill not work in this example. ```std::sort()``` is implemented to work with a **random access iterator**, which list does not provide. Instead it has its own ```list::sort()```\nand ```list::unique()``` member functions.","metadata":{},"id":"e9140c15"},{"cell_type":"markdown","source":"***\n**Example 2:** Performing reductions on an array\n\nThe STL also provides some algorithms for performing numeric operations. For these we need to include ```<numeric>```.","metadata":{},"id":"7856aa32"},{"cell_type":"code","source":"%%file accumulate.cpp\n\n#include <numeric>\n#include <vector>\n#include <iostream>\n\nint alternate( int a, int b ) {\n static bool odd = false; // static preserves value of local variable\n if( odd ) {\n odd = false;\n return a-b;\n }\n else {\n odd = true;\n return a+b;\n }\n}\n\nint main() {\n\n std::vector<int> v{1, 2, 3, 4, 5};\n \n int gs = std::accumulate( v.begin(), v.end(), 0 );\n std::cout << \"sum is \" << gs << std::endl;\n\n int check = std::accumulate( v.begin(), v.end(), -15 );\n if( check == 0 ) std::cout << \"checks out\" << std::endl;\n \n int prod = std::accumulate( v.begin(), v.end(), 1, std::multiplies<int>() );\n std::cout << \"5! = \" << prod << std::endl;\n\n int alt = std::accumulate( v.begin(), v.end(), 0, alternate );\n std::cout << \"Alternating sum gives \" << alt << std::endl;\n // 0 + 1 - 2 + 3 - 4 + 5\n}","metadata":{"trusted":true},"execution_count":30,"outputs":[{"name":"stdout","text":"Writing accumulate.cpp\n","output_type":"stream"}],"id":"bed09ecd"},{"cell_type":"code","source":"!g++ accumulate.cpp","metadata":{"trusted":true},"execution_count":31,"outputs":[],"id":"16a6d2e8"},{"cell_type":"code","source":"!./a.out","metadata":{"trusted":true},"execution_count":32,"outputs":[{"name":"stdout","text":"sum is 15\nchecks out\n5! = 120\nAlternating sum gives 3\n","output_type":"stream"}],"id":"015eb80f"},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[],"id":"1efec163"}]} \ No newline at end of file +{ + "cells": [ + { + "cell_type": "markdown", + "id": "bac1d62f", + "metadata": {}, + "source": [ + "# STL - Part 2 : More Containers & Algorithms" + ] + }, + { + "cell_type": "markdown", + "id": "efdc5616", + "metadata": {}, + "source": [ + "#### Sets" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "c2848a05", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 appears 0 times\n", + "1 appears 1 times\n", + "2 appears 1 times\n", + "3 appears 0 times\n", + "4 appears 1 times\n", + "5 appears 1 times\n", + "6 appears 0 times\n", + "7 appears 1 times\n" + ] + } + ], + "source": [ + "#include <iostream>\n", + "#include <set>\n", + "\n", + "std::set< int > s = {1, 7, 4, 8, 2}; // create a set container and fill it\n", + "\n", + "s.insert(5); // insert another element\n", + "s.insert(4);\n", + "\n", + "// check how often an element is inside the set\n", + "for ( int i = 0; i < 8; ++i ) {\n", + " std::cout << i << \" appears \" << s.count( i ) << \" times\\n\";\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "44573775", + "metadata": {}, + "source": [ + "**Remarks:**\n", + "- Although we inserted **4** twice, it is only stored once in the set data structure. Just like a mathematical set a ```std::set``` can contain a specific object only once.\n", + "- Hence, ```count()``` will always return either 0 or 1.\n", + "- This shows that ```std::set``` is no sequence container.\n", + "- Instead it stores its elements in a **sorted** fashion. This guarantees logarithmic complexity for element access." + ] + }, + { + "cell_type": "markdown", + "id": "a415d236", + "metadata": {}, + "source": [ + "Of course we can store various kinds of objects in a set ..." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2213e98e", + "metadata": {}, + "outputs": [], + "source": [ + "struct myPair {\n", + " myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {};\n", + " int fir_;\n", + " int sec_;\n", + "};\n", + "\n", + "std::set< myPair > pairs; " + ] + }, + { + "cell_type": "markdown", + "id": "725387bc", + "metadata": {}, + "source": [ + "... but there is a caveat. Check what happens, when we try to insert an object of type ```myPair``` into the set:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "51fd5597", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "In file included from input_line_5:1:\n", + "In file included from /srv/conda/envs/notebook/include/xeus/xinterpreter.hpp:13:\n", + "In file included from /srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/functional:49:\n", + "/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_function.h:386:20: error: invalid operands to binary expression ('const __cling_N54::myPair' and 'const __cling_N54::myPair')\n", + " { return __x < __y; }\n", + " ~~~ ^ ~~~\n", + "/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_tree.h:2100:13: note: in instantiation of member function 'std::less<__cling_N54::myPair>::operator()' requested here\n", + " __comp = _M_impl._M_key_compare(__k, _S_key(__x));\n", + " ^\n", + "/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_tree.h:2153:4: note: in instantiation of member function 'std::_Rb_tree<__cling_N54::myPair, __cling_N54::myPair, std::_Identity<__cling_N54::myPair>, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::_M_get_insert_unique_pos' requested here\n", + " = _M_get_insert_unique_pos(_KeyOfValue()(__v));\n", + " ^\n", + "/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_set.h:521:9: note: in instantiation of function template specialization 'std::_Rb_tree<__cling_N54::myPair, __cling_N54::myPair, std::_Identity<__cling_N54::myPair>, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::_M_insert_unique<__cling_N54::myPair>' requested here\n", + " _M_t._M_insert_unique(std::move(__x));\n", + " ^\n", + "input_line_12:2:8: note: in instantiation of member function 'std::set<__cling_N54::myPair, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::insert' requested here\n", + " pairs.insert( myPair(1,2) );\n", + " ^\n", + "In file included from input_line_5:1:\n", + "In file included from /srv/conda/envs/notebook/include/xeus/xinterpreter.hpp:17:\n", + "In file included from /srv/conda/envs/notebook/include/xeus/xcomm.hpp:15:\n", + "In file included from /srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/map:60:\n", + "/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_tree.h:777:2: error: static_assert failed \"comparison object must be invocable with two arguments of key type\"\n", + " static_assert(__is_invocable<_Compare&, const _Key&, const _Key&>{},\n", + " ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", + "/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_tree.h:2100:41: note: in instantiation of member function 'std::_Rb_tree<__cling_N54::myPair, __cling_N54::myPair, std::_Identity<__cling_N54::myPair>, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::_S_key' requested here\n", + " __comp = _M_impl._M_key_compare(__k, _S_key(__x));\n", + " ^\n", + "/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_tree.h:2153:4: note: in instantiation of member function 'std::_Rb_tree<__cling_N54::myPair, __cling_N54::myPair, std::_Identity<__cling_N54::myPair>, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::_M_get_insert_unique_pos' requested here\n", + " = _M_get_insert_unique_pos(_KeyOfValue()(__v));\n", + " ^\n", + "/srv/conda/envs/notebook/bin/../lib/gcc/../../x86_64-conda-linux-gnu/include/c++/9.4.0/bits/stl_set.h:521:9: note: in instantiation of function template specialization 'std::_Rb_tree<__cling_N54::myPair, __cling_N54::myPair, std::_Identity<__cling_N54::myPair>, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::_M_insert_unique<__cling_N54::myPair>' requested here\n", + " _M_t._M_insert_unique(std::move(__x));\n", + " ^\n", + "input_line_12:2:8: note: in instantiation of member function 'std::set<__cling_N54::myPair, std::less<__cling_N54::myPair>, std::allocator<__cling_N54::myPair> >::insert' requested here\n", + " pairs.insert( myPair(1,2) );\n", + " ^\n" + ] + }, + { + "ename": "Interpreter Error", + "evalue": "", + "output_type": "error", + "traceback": [ + "Interpreter Error: " + ] + } + ], + "source": [ + "pairs.insert( myPair(1,2) );" + ] + }, + { + "cell_type": "markdown", + "id": "2ee8f731", + "metadata": {}, + "source": [ + "**What went wrong?**\n", + "\n", + "As the set stores its elements in a **sorted** fashion it needs some way to **order** them.\n", + "By default the standard ```<``` relation is used.\n", + "\n", + "That does not work for our ```myPair``` data type.\n", + "\n", + "We need to define our own comparison operator for the class.\n", + "\n", + "There are plenty ways of doing that. Below we will use a free function for it." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "e8c29594", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing demo.cpp\n" + ] + } + ], + "source": [ + "%%file demo.cpp\n", + "\n", + "#include <iostream>\n", + "#include <set>\n", + "\n", + "struct myPair {\n", + " myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {};\n", + " int fir_;\n", + " int sec_;\n", + "};\n", + "\n", + "// our comparison function will return true, if the sum of the squares\n", + "// of the values in left is smaller than that in right (problem with tie-breaking?)\n", + "bool cmp( const myPair& left, const myPair& right ) {\n", + " int val1 = left.fir_ * left.fir_ + left.sec_ * left.sec_;\n", + " int val2 = right.fir_ * right.fir_ + right.sec_ * right.sec_;\n", + " return val1 < val2;\n", + "}\n", + "\n", + "int main() {\n", + " \n", + " // create two objects\n", + " myPair p1( 1, 2 );\n", + " myPair p2( 3, 4 );\n", + "\n", + " // compare them\n", + " std::cout << std::boolalpha;\n", + " std::cout << \"p1 < p2 is \" << cmp( p1, p2 ) << std::endl;\n", + " std::cout << \"p2 < p1 is \" << cmp( p2, p1 ) << std::endl;\n", + "\n", + " // a free function in C/C++ is represented by the address of its machine code in memory;\n", + " // thus, the type of argument is a function pointer;\n", + " // we need to pass that info as a second template argument;\n", + " // decltype returns the type of an expression\n", + " std::set< myPair, decltype( cmp )* > pairs( cmp );\n", + "\n", + " // alternatively we could do it ourselves; note that the (*) is important!\n", + " // but that way is not very C++-ish\n", + " // std::set< myPair, bool (*)( const myPair&, const myPair& ) > pairs( cmp );\n", + " \n", + " // now insertion will work\n", + " pairs.insert( p1 );\n", + " pairs.insert( p2 );\n", + "\n", + " std::cout << \"insertion successful\" << std::endl;\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "0a0207dd", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ demo.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "68e1df4b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "p1 < p2 is true\n", + "p2 < p1 is false\n", + "insertion successful\n" + ] + } + ], + "source": [ + "!./a.out" + ] + }, + { + "cell_type": "markdown", + "id": "f8b3109b", + "metadata": {}, + "source": [ + "**Note:** \n", + "The STL offers a variant **```std::unordered_set```** that stores its elements in an unsorted fashion. However, that would not solve our problem. Instead of a **comparison** we then would need to implement a **hashing function**." + ] + }, + { + "cell_type": "markdown", + "id": "59ab93ca", + "metadata": {}, + "source": [ + "***\n", + "The way we added the new element in the example, i.e. via\n", + "\n", + "```pairs.insert( myPair(1,2) );```\n", + "\n", + "again induced a copy operation. As with ```vector``` and ```list``` we could use ```emplace()``` instead.\n", + "\n", + "For demonstration purposes we make the constructor of ```myPair``` verbose." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "bdda6c33", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting demo.cpp\n" + ] + } + ], + "source": [ + "%%file demo.cpp\n", + "\n", + "#include <iostream>\n", + "#include <set>\n", + "\n", + "struct myPair {\n", + " myPair( int fir, int sec ) : fir_( fir ), sec_( sec ) {\n", + " std::cout << \"(\" << fir_ << \",\" << sec_ << \") constructed\" << std::endl;\n", + " };\n", + " \n", + " int fir_;\n", + " int sec_;\n", + "};\n", + "\n", + "// our comparison function: will return true, if the square of the values\n", + "// in left is smaller than that in right\n", + "bool cmp( const myPair& left, const myPair& right ) {\n", + " int val1 = left.fir_ * left.fir_ + left.sec_ * left.sec_;\n", + " int val2 = right.fir_ * right.fir_ + right.sec_ * right.sec_;\n", + " return val1 < val2;\n", + "}\n", + "\n", + "int main() {\n", + " \n", + " std::set< myPair, decltype( cmp )* > pairs( cmp );\n", + "\n", + " pairs.emplace( 1, 2 );\n", + " pairs.emplace( 3, 4 );\n", + " pairs.emplace( 1, 2 );\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "8099d1a4", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ demo.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "5d491b27", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1,2) constructed\n", + "(3,4) constructed\n", + "(1,2) constructed\n" + ] + } + ], + "source": [ + "!./a.out" + ] + }, + { + "cell_type": "markdown", + "id": "8e256275", + "metadata": {}, + "source": [ + "#### Associative Containers\n", + "\n", + "Quoting Wikipedia:\n", + "\n", + "> In computer science, an **associative array**, **map**, **symbol table**, or **dictionary** is an abstract data type composed of a collection of **(key, value) pairs**, such that each possible key appears at most once in the collection.\n", + ">\n", + "> Operations associated with this data type allow to:\n", + ">\n", + ">- add a pair to the collection;\n", + ">- remove a pair from the collection;\n", + ">- modify an existing pair;\n", + ">- lookup a value associated with a particular key.\n", + "\n", + "The STL also offers associative containers. An example is ```std::map```." + ] + }, + { + "cell_type": "markdown", + "id": "fb3ef7bb", + "metadata": {}, + "source": [ + "Return to our example with the traffic light. Assume that we want to print the currect state of a specific traffic light. How to do that?\n", + "\n", + "Well, using an enumeration for the state we can use the classical switch-case-construct:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "59839aea", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing ampel.cpp\n" + ] + } + ], + "source": [ + "%%file ampel.cpp\n", + "\n", + "#include <iostream>\n", + "\n", + "typedef enum{ GREEN, YELLOW, RED, YELLOW_RED } trafficLight;\n", + "\n", + "void ampel( trafficLight tf ) {\n", + "\n", + " switch( tf ) {\n", + " case GREEN:\n", + " std::cout << \"Lights are green\" << std::endl;\n", + " break;\n", + " case YELLOW:\n", + " std::cout << \"Lights are yellow\" << std::endl;\n", + " break;\n", + " case RED:\n", + " std::cout << \"Lights are red\" << std::endl;\n", + " break;\n", + " case YELLOW_RED:\n", + " std::cout << \"Lights are yellow-red\" << std::endl;\n", + " break;\n", + " }\n", + "\n", + "}\n", + "\n", + "int main() {\n", + " trafficLight tf = GREEN;\n", + " ampel( tf );\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "76c8886d", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ ampel.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "731e7c94", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Lights are green\n" + ] + } + ], + "source": [ + "!./a.out" + ] + }, + { + "cell_type": "markdown", + "id": "08b68b2b", + "metadata": {}, + "source": [ + "Another (neater) way is to associate the state with a corresponding string" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "8fe484bf", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting ampel.cpp\n" + ] + } + ], + "source": [ + "%%file ampel.cpp\n", + "\n", + "#include <iostream>\n", + "#include <map>\n", + "\n", + "typedef enum{ GREEN, YELLOW, RED, YELLOW_RED } trafficLight;\n", + "\n", + "int main() {\n", + "\n", + " std::map< trafficLight, std::string > tf2str =\n", + " { { GREEN, \"green\" }, { YELLOW, \"yellow\" }, { RED, \"red\" },\n", + " { YELLOW_RED, \"yellow-red\" } };\n", + "\n", + " trafficLight tf = GREEN;\n", + "\n", + " std::cout << \"Lights are \" << tf2str[ tf ] << std::endl;\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "74251bd8", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ ampel.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "5b919ca3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Lights are green\n" + ] + } + ], + "source": [ + "!./a.out" + ] + }, + { + "cell_type": "markdown", + "id": "b1718cdd", + "metadata": {}, + "source": [ + "Another example, demonstrating additional features of ```std::map``` (converted from Gottschling, *Forschung mit modernem C++*)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "52f631d4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting constants.cpp\n" + ] + } + ], + "source": [ + "%%file constants.cpp\n", + "\n", + "#include <iostream>\n", + "#include <string>\n", + "#include <map>\n", + "#include <cmath>\n", + "\n", + "int main() {\n", + "\n", + " // create a map and fill it with some (key,value) pairs\n", + " std::map< std::string, double > constants = { {\"e\", std::exp(1.0)},\n", + " {\"pi\", 4.0*std::atan(1.0) }, {\"h\", 6.6e-34} };\n", + "\n", + " // subscript operator is overloaded to allow access via a key\n", + " std::cout << \"Value of Planck constant is \" << constants[ \"h\" ] << '\\n';\n", + " constants[ \"c\" ] = 299792458;\n", + "\n", + " // Hmmm, what happens here? No key \"k\" exists so far!\n", + " std::cout << \"Value of Coulomb constant is \" << constants[ \"k\" ] << '\\n';\n", + "\n", + " // find() allows to check for existance of a key; returns an iterator\n", + " // to the pair, if it is found\n", + " std::cout << \"Value of pi is \" << constants.find( \"pi\" )->second << '\\n';\n", + "\n", + " // if not it returns end\n", + " auto it_phi = constants.find( \"phi\" );\n", + " if ( it_phi != constants.end() ) {\n", + " std::cout << \"The golden ratio is \" << it_phi->second << '\\n';\n", + " }\n", + "\n", + " // can use at(), if we know the pair to exists, returns value for key\n", + " // will throw an \"out_of_range\" exception, if we were wrong\n", + " std::cout << \"Value of Euler constant is \" << constants.at( \"e\" ) << \"\\n\\n\";\n", + "\n", + " // range-based loop\n", + " for ( auto& c: constants ) {\n", + " std::cout << \"Value of \" << c.first << \" is \" << c.second << '\\n';\n", + " }\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "aaba61ba", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ constants.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "3f9362c9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Value of Planck constant is 6.6e-34\n", + "Value of Coulomb constant is 0\n", + "Value of pi is 3.14159\n", + "Value of Euler constant is 2.71828\n", + "\n", + "Value of c is 2.99792e+08\n", + "Value of e is 2.71828\n", + "Value of h is 6.6e-34\n", + "Value of k is 0\n", + "Value of pi is 3.14159\n" + ] + } + ], + "source": [ + "!./a.out" + ] + }, + { + "cell_type": "markdown", + "id": "a7e8490c", + "metadata": {}, + "source": [ + "**Note:** \n", + "As with ```set``` there is also a variant of ```map``` that uses hashing instead of ordered storage and is called ```unordered_map```." + ] + }, + { + "cell_type": "markdown", + "id": "2032e7f2", + "metadata": {}, + "source": [ + "#### Algorithm\n", + "\n", + "The STL supports also various algorithms that work on the entries in a container. The advantage again is that these save us implementation and will (potentially) work for various kinds of containers.\n", + "\n", + "We will briefly look at two examples." + ] + }, + { + "cell_type": "markdown", + "id": "4c239bfa", + "metadata": {}, + "source": [ + "**Example 1:** Remove double entries from a sequence" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "aed454ce", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing uniq.cpp\n" + ] + } + ], + "source": [ + "%%file uniq.cpp\n", + "\n", + "#include <algorithm>\n", + "#include <vector>\n", + "#include <iostream>\n", + "\n", + "using Container = std::vector<int>;\n", + "\n", + "void print( const Container& box, const std::string& note ) {\n", + " std::cout << \"( \";\n", + " for( int w: box ) std::cout << w << ' ';\n", + " std::cout << \") \" << note << std::endl;\n", + "}\n", + " \n", + "int main() {\n", + "\n", + " Container box{ 3, 5, 2, 4, 1, 2, 1 };\n", + " print( box, \"<- unsorted\" );\n", + "\n", + " sort( box.begin(), box.end() );\n", + " print( box, \"<- sorted\" );\n", + "\n", + " Container::iterator last = unique( begin(box), end(box) );\n", + " print( box, \"<- happened in-place\" );\n", + "\n", + " box.resize( distance( box.begin(), last ) );\n", + " print( box, \" <- truncated to new length\" );\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "57c92377", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ uniq.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "b190c1c6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "( 3 5 2 4 1 2 1 ) <- unsorted\n", + "( 1 1 2 2 3 4 5 ) <- sorted\n", + "( 1 2 3 4 5 4 5 ) <- happened in-place\n", + "( 1 2 3 4 5 ) <- truncated to new length\n" + ] + } + ], + "source": [ + "!./a.out" + ] + }, + { + "cell_type": "markdown", + "id": "e9140c15", + "metadata": {}, + "source": [ + "**Note:**\n", + "\n", + "Replacing ```vector``` by ```list``` via\n", + "\n", + " using Container = std::list<int>;\n", + "\n", + "will not work in this example. ```std::sort()``` is implemented to work with a **random access iterator**, which list does not provide. Instead it has its own ```list::sort()```\n", + "and ```list::unique()``` member functions." + ] + }, + { + "cell_type": "markdown", + "id": "7856aa32", + "metadata": {}, + "source": [ + "***\n", + "**Example 2:** Performing reductions on an array\n", + "\n", + "The STL also provides some algorithms for performing numeric operations. For these we need to include ```<numeric>```." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "bed09ecd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing accumulate.cpp\n" + ] + } + ], + "source": [ + "%%file accumulate.cpp\n", + "\n", + "#include <numeric>\n", + "#include <vector>\n", + "#include <iostream>\n", + "\n", + "int alternate( int a, int b ) {\n", + " static bool odd = false; // static preserves value of local variable\n", + " if( odd ) {\n", + " odd = false;\n", + " return a-b;\n", + " }\n", + " else {\n", + " odd = true;\n", + " return a+b;\n", + " }\n", + "}\n", + "\n", + "int main() {\n", + "\n", + " std::vector<int> v{1, 2, 3, 4, 5};\n", + " \n", + " int gs = std::accumulate( v.begin(), v.end(), 0 );\n", + " std::cout << \"sum is \" << gs << std::endl;\n", + "\n", + " int check = std::accumulate( v.begin(), v.end(), -15 );\n", + " if( check == 0 ) std::cout << \"checks out\" << std::endl;\n", + " \n", + " int prod = std::accumulate( v.begin(), v.end(), 1, std::multiplies<int>() );\n", + " std::cout << \"5! = \" << prod << std::endl;\n", + "\n", + " int alt = std::accumulate( v.begin(), v.end(), 0, alternate );\n", + " std::cout << \"Alternating sum gives \" << alt << std::endl;\n", + " // 0 + 1 - 2 + 3 - 4 + 5\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "16a6d2e8", + "metadata": {}, + "outputs": [], + "source": [ + "!g++ accumulate.cpp" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "015eb80f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "sum is 15\n", + "checks out\n", + "5! = 120\n", + "Alternating sum gives 3\n" + ] + } + ], + "source": [ + "!./a.out" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1efec163", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "C++14", + "language": "C++14", + "name": "xcpp14" + }, + "language_info": { + "codemirror_mode": "text/x-c++src", + "file_extension": ".cpp", + "mimetype": "text/x-c++src", + "name": "c++", + "version": "14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/08_Functors+Lambdas.ipynb b/notebooks/08_Functors+Lambdas.ipynb index 90682ed36058bfe3ae5ede117cf9de88b6b2dbc3..f0c89ded37556db41667ac172757a94fe5e6f42d 100644 --- a/notebooks/08_Functors+Lambdas.ipynb +++ b/notebooks/08_Functors+Lambdas.ipynb @@ -222,7 +222,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 11, "id": "856ee747", "metadata": {}, "outputs": [ @@ -230,7 +230,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Writing functor.cpp\n" + "Overwriting functor.cpp\n" ] } ], @@ -264,6 +264,7 @@ " myPair p1( 1, 2 );\n", " myPair p2( 3, 4 );\n", "\n", + " std::cout << std::boolalpha;\n", " std::cout << \"p1 < p2 is \" << cmp( p1, p2 ) << std::endl;\n", " std::cout << \"p2 < p1 is \" << cmp( p2, p1 ) << std::endl;\n", "\n", @@ -277,7 +278,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 12, "id": "4adb7f0b", "metadata": {}, "outputs": [], @@ -287,7 +288,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 13, "id": "f9bfde7f", "metadata": {}, "outputs": [ @@ -297,8 +298,8 @@ "text": [ "(1,2) constructed\n", "(3,4) constructed\n", - "p1 < p2 is 1\n", - "p2 < p1 is 0\n", + "p1 < p2 is true\n", + "p2 < p1 is false\n", "(3,4) constructed\n", "(5,6) constructed\n" ]