#include #include #include #include #include #include #include #include using namespace std; using stat = tuple; using tupv = vector; void read_numbers(tupv& v); void sort_numbers(tupv& v); void print_numbers(tupv const& v); // // In this example code the "cout" statements double as both a clue to // where the program is and as a comment. // int main(int argc, char* argv[]) { cout << "Just print entire command line." << endl; for (int i{0}; i < argc; ++i) { cout << argv[i] << " "; } cout << endl << endl; //---------------------------------------------------------------------- // Our first problem: // Print all numbers on command line in sorted order. //---------------------------------------------------------------------- cout << "Solution 1. Put arguments in a empty vector." << endl << "Skip argv[0] as it's the program name (a.out?)" << endl; vector v1; for (int i{1}; i < argc; ++i) { // v1[i] = argv[i]; // Silent ERROR! v1 is empty! // v1.at(i) = argv[i]; // Proper ERROR! v1 is empty! v1.push_back(argv[i]); // Correct, append to v1 } cout << "Sort with default string comparison. (INCORRECT)" << endl; sort(v1.begin(), v1.end()); // Logic error! What's wrong? cout << "Printing to cout with normal indexing." << endl; for (unsigned int i{0}; i < v1.size(); ++i) { cout << v1.at(i) << ", "; } cout << endl << endl; //---------------------------------------------------------------------- cout << "Solution 2. Put arguments in a sized vector." << endl << "Construct with (5) to get initial size 5." << endl << "If you initialize with {5} only 5 is inserted (size 1)." << endl; vector v2(argc-1); for (int i{1}; i < argc; ++i) { v2.at( i-1 ) = argv[i]; // Correct, v2 is large enough } cout << "Sort with lambda expression to compare two items." << endl; sort(v2.begin(), v2.end(), [](string const& a, string const& b)->bool { return stoi(a) < stoi(b); } ); cout << "Printing to cout with a const_iterator." << endl; for (vector::const_iterator i{v2.cbegin()}; i != v2.cend(); ++i) { cout << *i << ", "; } cout << endl << endl; //---------------------------------------------------------------------- cout << "Solution 3. Put arguments in a sized integer vector." << endl; vector v3(argc-1); for (int i{1}; i < argc; ++i) { v3.at( i-1 ) = stoi(argv[i]); } cout << "Sort with default integer comparison." << endl; sort(v3.begin(), v3.end()); cout << "Printing to cout with range based for loop." << endl; for (int const& i : v3) { cout << i << ", "; } cout << endl << endl; //---------------------------------------------------------------------- cout << "Solution 4. Convert command line to a vector immediately." << endl << "Vectors can be initialized from a range specified by " << endl << "anything that behave as an iterator (can be incremented " << endl << "and dereferenced)." << endl; vector v4( &argv[1], &argv[argc] ); //vector v4( &argv[1], &argv[argc] ); // Works too and better! cout << "Sort with default (char*) comparison. (INCORRECT)" << endl; sort(v4.begin(), v4.end()); // Logic error? cout << "Print to cout with a for_each algorithm." << endl; for_each(v4.cbegin(), v4.cend(), [](string const& str)->void { cout << str << ", "; }); cout << endl << endl; //---------------------------------------------------------------------- cout << "Solution 5. Transform to back_inserted integer vector." << endl; vector v5; // Created empty transform(&argv[1], &argv[argc], back_inserter(v5), [](string const& s)->int { // conversion from (char*) to (string) happen automatically! // convert the (string) to (int) and return the integer return stoi(s); }); cout << "Sort with default integer comparison." << endl; sort(v5.begin(), v5.end()); cout << "Print to cout with ostream_iterator" << endl; copy(v5.cbegin(), v5.cend(), ostream_iterator(cout, ", ")); cout << endl << endl; //---------------------------------------------------------------------- cout << "Solution 6. Sort argument C-array directly." << endl; sort( &argv[1], &argv[argc], [](char const* a, char const* b)->bool { // convert (char*) to (int) before comparing // since stoi take (string) as parameter (char*) // will be auto-converted to (string) first return stoi(a) < stoi(b); } ); cout << "Print to cout with ostream_iterator" << endl; copy( &argv[1], &argv[argc], ostream_iterator(cout, ", ")); cout << endl << endl; //---------------------------------------------------------------------- // Our second problem: // Read numbers from user until user press Ctrl-D. // Print all unique numbers in ascending order. //---------------------------------------------------------------------- int num; //---------------------------------------------------------------------- cout << "Solution 1. Insert in vector if not already there." << endl; vector s1; // Ctrl-D means that end-of-file will be set on cin // (cin >> num) will "return false" on any failure while (cin >> num) { if (find(s1.cbegin(), s1.cend(), num) == s1.cend()) { s1.push_back(num); } } cin.clear(); // clear end-of-file error on cin sort(s1.begin(), s1.end()); cout << "Print all unique numbers in ascending order." << endl; copy(s1.cbegin(), s1.cend(), ostream_iterator(cout, ", ")); cout << endl; //---------------------------------------------------------------------- cout << "Solution 2. Insert in vector and then filter duplicates." << endl; vector s2; // Ctrl-D means that end-of-file will be set on cin // (cin >> num) will "return false" on any failure while (cin >> num) { s2.push_back(num); } cin.clear(); // clear end-of-file error on cin // Remove duplicates on a sorted range // Unique require sorted range, and return an iterator // that point to first duplicate element sort(s2.begin(), s2.end()); s2.erase( unique(s2.begin(), s2.end()) , s2.end()); cout << "Print all unique numbers in ascending order." << endl; copy(s2.cbegin(), s2.cend(), ostream_iterator(cout, ", ")); cout << endl; //---------------------------------------------------------------------- cout << "Solution 3. Let a std::set sort and filter duplicates." << endl; set s3; while (cin >> num) { s3.insert(num); } cin.clear(); cout << "Print all unique numbers in ascending order." << endl; copy(s3.cbegin(), s3.cend(), ostream_iterator(cout, ", ")); cout << endl; //---------------------------------------------------------------------- // Our third problem: // Read numbers from user until user press Ctrl-D. // Print all unique numbers in descending order, // and how many times each number occurred. //---------------------------------------------------------------------- //---------------------------------------------------------------------- cout << "Solution 1. Use a map with manual conditional insertion." << endl; using my_map = map; my_map m1; while (cin >> num) { my_map::iterator i = m1.find(num); if ( i == m1.end() ) { m1.insert(make_pair(num, 1)); } else { (*i).second += 1; // Access the found value, // i->second += 1; // Alternate syntax not covered yet // m0.at(num) += 1; // Or find the key-value pair again } } cin.clear(); cout << "Printing the map with a const_iterator loop." << endl; for (my_map::const_iterator i = m1.cbegin(); i != m1.cend(); ++i) { cout << setw(5) << (*i).first << setw(5) << (*i).second << endl; // We did not cower operator-> yet but it just "syntactic sugar" // i->first actually mean (*i).first // "Go to the place i refer to, access 'first' there." // cout << setw(5) << i->first << setw(5) << i->second << endl; } //---------------------------------------------------------------------- cout << "Solution 2. Use brackets on the map to find and insert." << endl; my_map m2; while (cin >> num) { ++m2[num]; } cin.clear(); cout << "Printing the map with a range based for loop." << endl; // a map actually store a pair for (pair const& p : m2) { cout << setw(5) << p.first << setw(5) << p.second << endl; } //---------------------------------------------------------------------- // Our fourth problem: // Solve it with functions and vector containing tuples. //---------------------------------------------------------------------- cout << "Solution 3. Use functions, and a vector with tuples." << endl; tupv v; // The "using tupv = ..." is found at beginning of this file. read_numbers(v); sort_numbers(v); print_numbers(v); return 0; } // Accept reference to the map, since we will modify (fill) it. void read_numbers(tupv& v) { int num; while (cin >> num) { tupv::iterator i = find_if(v.begin(), v.end(), [num](stat const& t)->bool { return num == get<0>(t); }); if (i == v.end()) v.push_back(make_tuple(num, 1)); else get<1>(*i) += 1; } } // Accept reference to the map, since we will modify (sort) it. void sort_numbers(tupv& v) { sort(v.begin(), v.end(), [](stat const& a, stat const& b)->bool { return get<0>(a) < get<0>(b); }); } // Accept const reference to the map, since we will not modify it. void print_numbers(tupv const& v) { // for (tupv::const_iterator i = v.cbegin(); i != v.cend(); ++i) // for_each(v.cbegin(), v.cend(), [](stat const& i) for (stat const& i : v) { cout << setw(5) << get<0>(i) << setw(5) << get<1>(i) << endl; }//); auto i = 0, j = 0; i = j = i; }