SL Practice

SL Practice#

Let’s do some more practice on using the standard library.

  1. In Homework #6, you wrote a function to find the maximum element in a vector. Let’s do that again, this time using std::ranges::max_element.

    Then use std::ranges::distance to find the index (just like we did with our Finding an element example).

    solution
    Listing 97 max_example.cpp#
    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    int main() {
    
        std::vector<int> vec{10, -1, -50, 101, 4, 0, 800, -250, 277, 8, 12};
    
        auto it_max = std::ranges::max_element(vec);
    
        std::cout << "maximum is " << *it_max << std::endl;
    
        // now find what index it is
    
        auto index = std::ranges::distance(vec.begin(), it_max);
    
        std::cout << "the index is " << index << std::endl;
    
    }
    

    The key point here is that max_element returns an iterator to the maximum element in the vector. We need to dereference it (using the * operator) to see the value it points to.

  2. We can use std::accumulate to sum the elements of a vector, or multiply them, or some other transformation.

    Write some code to find the sum of the elements and the product of the elements of a vector.

    solution
    Listing 98 accumulate_example.cpp#
    #include <iostream>
    #include <numeric>
    #include <vector>
    
    int main() {
    
        std::vector<int> vec{10, -1, -50, 101, 4, 2, 800, -250, 277, 8, 12};
    
        auto sum = std::accumulate(vec.begin(), vec.end(), 0.0);
    
        std::cout << "the sum is " << sum << std::endl;
    
        auto prod = std::accumulate(vec.begin(), vec.end(), 1,
                                    [] (const int& a, const int& b) {return a * b;});
    
        std::cout << "the product is " << prod << std::endl;
    
    }
    

    std::accumulate usually takes 4 arguments:

    • An iterator pointing to the beginning of the range to sum

    • An iterator pointing to one-past the end of the range to sum

    • An initial value for the accumulation

    • A function to do the operation that takes two arguments. The first is the current accumulated value and the second is an element in the vector.

    For our sum, we want to start with 0, and then we add to this. With no operator as the 4th argument, std::accumulate will do a sum, so that allows us to do this call:

    auto sum = std::accumulate(vec.begin(), vec.end(), 0.0);
    

    We could have used the C++ standard library std::plus function to be more explicit:

    auto sum = std::accumulate(vec.begin(), vec.end(), std::plus<int>{});
    

    or we could write our own (lambda) function and pass it in.

    For our product, we want to start with 1, since multiplying the first element by 1 will just give us the first element. In this example, we write a lambda-function. We could also use std::multiplies.

  3. In our Checking if any element matches example, we checked if any element in a vector was even. Let’s rewrite that using a lambda function.

    solution
    Listing 99 any_element_lambda.cpp#
    #include <vector>
    #include <algorithm>
    #include <iostream>
    
    
    int main() {
    
        std::vector<int> a{1, 3, 5, 7, 9, 11, 13};
        std::vector<int> b{1, 3, 5, 6, 7, 9, 11, 13};
    
        auto test = std::ranges::any_of(a, [] (int e) {return e % 2 == 0;});
        std::cout << "any of a are even? " << test << std::endl;
    
        auto test2 = std::ranges::any_of(b, [] (int e) {return e % 2 == 0;});
        std::cout << "any of b are even? " << test2 << std::endl;
    
    }
    

    In this example, our lambda function is simply:

    [] (int e) {return e % 2 == 0;}
    

    This doesn’t need to capture anything from the surrounding scope ([]) and works on a single element passed in ((int e)). This function is equivalent to our original:

    bool is_even(int e) {
        return e % 2 == 0;
    }