Is there a way to find the minimum odd element of a vector of integers without basically reimplementing std::min_element and without doing additional work like computing the vector of odd integers first?
While a custom comparison object suggested in another answer will be a simple solution for std::min_element (and similar) in particular, it won't work with all standard algorithms. A general approach that works with any standard algorithm is to define a custom iterator.
Customising, combining and extending standard algorithms can nearly always be achieved with iterators. Writing custom iterators from scratch involves a lot of boilerplate and unfortunately standard doesn't provide templates for many iterator adaptors. Boost does provide plenty of iterator adaptor templates, and in this case boost::filter_iterator should prove useful.
Instead of the more traditional iterator algorithms, you could use range algorithms instead.
Since C++20, there are a host of standard range adaptors for range algorithms which are easy to compose:
auto it = std::ranges::min_element(
container | std::views::filter(condition)
);
Note that at the moment of writing, only libstdc++ has implemented the ranges standard library.
A simple solution consists in using a custom comparator function with sd::min_element.
What should be added in the following code is to check that the obtained value is odd indeed, as mentioned by #MSalters in their answer and by #Kevin in a comment.
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v = {0, 3, 4, 1};
auto comp = [](int a, int b) {
if ((a%2) and (b%2 == 0)) return true;
if ((a%2 == 0) and (b%2)) return false;
return a < b;
};
auto min_odd = std::min_element (v.begin(), v.end(), comp);
std::cout << *min_odd << std::endl;
}
A C++20 solution:
std::vector<int> ints{0, 1, 2, 3, 4, 5};
auto odd = [](int i) { return bool(i % 2); };
auto e = std::ranges::min_element(ints | std::views::filter(odd));
Yes, that's not very hard. Implement a custom comparison that sorts each even element above all odd elements. You still need to sort the odd elements in their usual order, and at the end check that there was at least one odd element in the vector.
Related
I can't infer I can use std::set_difference from documentation, because it says sets should be ordered, which means they are not sets, but lists. Also all examples are about ordered lists, not sets.
How to know the truth?
std::set_difference is for use with arbitrary sorted inputs (pre-sorted std::vectors, std::lists, std::deques, plain array, etc.), it just happens to work with std::set (which is sorted) too.
If you're working with std::unordered_set (or std::set, and you're okay with operating in place), you'd just use the erase method to remove all elements from one such set from another to get the difference, e.g.:
for (const auto& elem : set_to_remove) {
myset.erase(elem);
}
You can also do it into a new set with std::copy_if; the recipe there is trivially adaptable to the case of symmetric difference (it's just two calls to std::copy_if, where each one runs on one input set, and is conditioned on the element not existing in other input set).
std::set is sorted. Check out the docs:
std::set is an associative container that contains a sorted set of
unique objects of type Key. Sorting is done using the key comparison
function Compare. Search, removal, and insertion operations have
logarithmic complexity. Sets are usually implemented as red-black
trees.
Therefore, you can use it in a same way as any other container that provides the required interface. The difference between std::set and e.g. std::vector is that std::set is sorting its elements on insertion and in case of std::vector you need to use std::sort function to get its elements sorted.
For example, if you need to std::set_difference for std::unordered_set, you can do it like this:
#include <set>
#include <iostream>
#include <algorithm>
#include <unordered_set>
int main() {
std::unordered_set<int> a {3, 1, 4, 6, 5, 9};
std::unordered_set<int> b {3, 1, 4};
std::set<int> c;
std::set<int> d;
std::copy(a.begin(), a.end(), std::inserter(c, c.end()));
std::copy(b.begin(), b.end(), std::inserter(d, d.end()));
std::vector<int> diff;
std::set_difference(c.begin(), c.end(), d.begin(), d.end(),
std::inserter(diff, diff.begin()));
for (auto const i : diff)
std::cout << i << ' ';
return 0;
}
See live
The task of removing elements with a certain property from a std::vector or other container lends itself to a functional style implementation: Why bother with loops, memory deallocation and moving data around correctly?
However the standard way of doing this in C++ seems to be the following idiom:
std::vector<int> ints;
...
ints.erase(
std::remove_if(ints.begin(),
ints.end(),
[](int x){return x < 0;}),
ints.end());
This example removes all elements less than zero from an integer vector.
I find it not only ugly but also easy to use incorrectly. It is clear that std::remove_if cannot change the size of the vector (as its name would suggest) because it only gets iterators passed. But many developers, including myself, don't get that in the beginning.
So is there a safer and hopefully more elegant way to achieve this? If not, why?
I find it not only ugly but also easy to use incorrectly.
Don't worry, we all did at the start.
It is clear that std::remove_if cannot change the size of the vector (as its name would suggest) because it only gets iterators passed. But many developers, including myself, don't get that in the beginning.
Same. It confuses everyone. It probably shouldn't have been called remove_if all those years ago. Hindsight, eh?
So is there a safer and hopefully more elegant way to achieve this?
No
If not, why?
Because this is the safest, most elegant way that preserves performance when deleting items from a container in which deleting an item invalidates iterators.
anticipating:
Anything I can do?
Yes, wrap this idiom into a function
template<class Container, class F>
auto erase_where(Container& c, F&& f)
{
return c.erase(std::remove_if(c.begin(),
c.end(),
std::forward<F>(f)),
c.end());
}
The call in the motivating example then becomes:
auto is_negative = [](int x){return x < 0;};
erase_where(ints, is_negative);
or
erase_where(ints, [](int x){return x < 0;});
This will become available in a C++17-ready compiler soon through the std::experimental::erase_if algorithm:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <experimental/vector>
int main()
{
std::vector<int> ints { -1, 0, 1 };
std::experimental::erase_if(ints, [](int x){
return x < 0;
});
std::copy(ints.begin(), ints.end(), std::ostream_iterator<int>(std::cout, ","));
}
Live Example that prints 0,1
When using STL's functions like sort() or min_element() I always have to specify the range by begin and end explicitly:
void range_example()
{
std::vector<int> list = {7, 3, 9, 1, 5, 2};
auto found_element = std::min_element(list.begin(), list.end());
std::cout << *found_element << std::endl;
}
This makes sense if I intend to work only on part of my container, but more often I need the functions to work on the whole container. Is there a reason why there isn't an overloaded function that allows for this:
std::vector<int> list = {7, 3, 9, 1, 5, 2};
auto found_element = std::min_element(list);
Is there a way to accomplish a function call for the total range of a container that I have overlooked?
EDIT: I'm aware that I can encapsulate that in a function myself, but because this must be done for all functions I'd like to avoid that if there is a better way.
Most of the time, the standard library is designed to provide the minimal interface necessary to accomplish all the tasks required, i.e. it tries to avoid interface bloat. You can operate on a whole container when the algorithm accepts a pair of iterators, but you could not operate on a subrange if the algorithm accepted a container. So the iterator pair is more fundamental, and so that's what the standard library provides. Convenience functions are usually not included.
However, you're certainly not the first person to think this way, and there's the entire Boost.Range library devoted to treating a range (both a container and an arbitrary range) as a single entity instead of a pair of iterators.
There is also a formal proposal to incorporate Eric Niebler's range library in a future version of the C++ standard library.
This is because STL algorithms are container-independent. Iterators provide a uniform way for them to work, with the only limitation being what are the guarantees this algorithm requires from these iterators.
For example, if you want to do a linear search for min_element(), you only need forward iterators (i.e. they only have to support operator++). So, you can write one simple templated implementation that will work with essentially every container, despite how the container is implemented under the hood.
You could overload functions to take only the container and apply begin() and end() on them, but this would mean that you have one more interface to remember.
Edit
I suppose there are a few other arguments that could be made. Since STL was all about mathematical beauty and emphasis that algorithms are separate from containers, always passing iterators would reinforce this notion.
On the other hand, in terms of the C++ language as a whole, one of the main goals of Stroustrup was to educate developers. The full power of STL algorithms comes from the ability to pass arbitrary iterator ranges, but most of the time you want to operate on the whole container. If you provided overloads for the whole container, it could be argued that a large number of people would never bother to learn to use range versions, because it would be precisely those versions that would fall into "another interface to remember" category.
The practical reason why container or range overloads hasn't been done yet has to do with the concepts proposal.
Right now, the algorithms take a bunch of template parameters, and place requirements on them. If you pass types that don't match the requirements, they can fail to compile or just fail to work properly.
Overloads almost always simply involve a different number of parameters.
If we where to add container/range overloads, then we'd either have to give them new names (ick), or modify the existing algorithms to be overload-smart. A (iterator, iterator, value) overload and a (range, value, function) overload have the same number of arguments, and which one is being called could easily get confusing to the compiler (and unexpected results could occur).
While we could go and specify overload constraints on all existing algorithms one-by-one, then add in the overloads for ranges, at this point the code and requirements would be ugly. After concepts is added to the language, we'll both hopefully have a set of concise concepts that describe what the parameters should be, and a language feature that makes the implementation easy and clean.
It may turn out that these algorithms may not practically be overloads of the existing algorithms, due to compatibility reasons or what have you, but even this will be easier to work out.
Originally, iterators were sufficient, and they decouple containers from algorithms. Ranges could have been added then, but the language machinery for clean range interpretation of containers was somewhat lacking (decltype, for example, is useful), and it wasn't strictly required. Since then, range support has been desired, but it isn't easy to do it cleanly, and there is (on the horizon) a language extension that will make it much cleaner and easier.
You could implement your own:
template<class Container>
typename Container::iterator min_element(Container& c) {
using std::begin;
using std::end;
return std::min_element(begin(c), end(c));
}
std::vector<int> list = {7, 3, 9, 1, 5, 2};
auto found_element = min_element(list);
For completeness:
template<class Container>
typename std::conditional<
std::is_const<Container>::value,
typename Container::const_iterator,
typename Container::iterator>::type min_element(Container& c) {
using std::begin;
using std::end;
return std::min_element(begin(c), end(c));
}
and to support arrays:
template<typename T, size_t N>
T* min_element(T (&arr)[N]) { return std::min_element(arr, arr + N); }
This is one of the times where I think it is fine to use macros. Just make sure that computing the expression inside the macro has no side effects.
#include <boost/preprocessor/punctuation/comma.hpp>
// this is just: #define BOOST_PP_COMMA() ,
#define RANGE_ARGS( container ) container.begin ( ) BOOST_PP_COMMA() container.end ( )
#define RANGE_ARGS_C( container ) container.cbegin ( ) BOOST_PP_COMMA() container.cend ( )
#define RANGE_ARGS_R( container ) container.rbegin ( ) BOOST_PP_COMMA() container.rend ( )
#define RANGE_ARGS_CR( container ) container.crbegin ( ) BOOST_PP_COMMA() container.crend ( )
This yields, in your case:
std::vector<int> list = {7, 3, 9, 1, 5, 2};
auto const found_element = std::min_element( RANGE_ARGS_C(list) );
It is easy to define such a function yourself. For example
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
template <class T>
decltype( auto ) min_element( T &c )
{
return std::min_element( std::begin( c ), std::end( c ) );
}
int main()
{
int a[] = { 5, 7, 3, 1, 9, 6 };
std::cout << *min_element( a ) << std::endl;
std::vector<int> v( std::begin( a ), std::end( a ) );
std::cout << *min_element( v ) << std::endl;
}
The program output is
1
1
I made such a suggestion for algorithms std::sort and std::reverse. You can read about it in my personal forum that I support like my perosnal internet page.
here
Though it is written in Russian you can translate it for example with Bing or google.
Both can be used to apply a function to a range of elements.
On a high level:
std::for_each ignores the return value of the function, and
guarantees order of execution.
std::transform assigns the return value to the iterator, and does
not guarantee the order of execution.
When do you prefer using the one versus the other? Are there any subtle caveats?
std::transform is the same as map. The idea is to apply a function to each element in between the two iterators and obtain a different container composed of elements resulting from the application of such a function. You may want to use it for, e.g., projecting an object's data member into a new container. In the following, std::transform is used to transform a container of std::strings in a container of std::size_ts.
std::vector<std::string> names = {"hi", "test", "foo"};
std::vector<std::size_t> name_sizes;
std::transform(names.begin(), names.end(), std::back_inserter(name_sizes), [](const std::string& name) { return name.size();});
On the other hand, you execute std::for_each for the sole side effects. In other words, std::for_each closely resembles a plain range-based for loop.
Back to the string example:
std::for_each(name_sizes.begin(), name_sizes.end(), [](std::size_t name_size) {
std::cout << name_size << std::endl;
});
Indeed, starting from C++11 the same can be achieved with a terser notation using range-based for loops:
for (std::size_t name_size: name_sizes) {
std::cout << name_size << std::endl;
}
Your high level overview
std::for_each ignores the return value of the function and guarantees order of execution.
std::transform assigns the return value to the iterator, and does not guarantee the order of execution.
pretty much covers it.
Another way of looking at it (to prefer one over the other);
Do the results (the return value) of the operation matter?
Is the operation on each element a member method with no return value?
Are there two input ranges?
One more thing to bear in mind (subtle caveat) is the change in the requirements of the operations of std::transform before and after C++11 (from en.cppreference.com);
Before C++11, they were required to "not have any side effects",
After C++11, this changed to "must not invalidate any iterators, including the end iterators, or modify any elements of the ranges involved"
Basically these were to allow the undetermined order of execution.
When do I use one over the other?
If I want to manipulate each element in a range, then I use for_each. If I have to calculate something from each element, then I would use transform. When using the for_each and transform, I normally pair them with a lambda.
That said, I find my current usage of the traditional for_each being diminished somewhat since the advent of the range based for loops and lambdas in C++11 (for (element : range)). I find its syntax and implementation very natural (but your mileage here will vary) and a more intuitive fit for some use cases.
Although the question has been answered, I believe that this example would clarify the difference further.
for_each belongs to non-modifying STL operations, meaning that these operations do not change elements of the collection or the collection itself. Therefore, the value returned by for_each is always ignored and is not assigned to a collection element.
Nonetheless, it is still possible to modify elements of collection, for example when an element is passed to the f function using reference. One should avoid such behavior as it is not consistent with STL principles.
In contrast, transform function belongs to modifying STL operations and applies given predicates (unary_op or binary_op) to elements of the collection or collections and store results in another collection.
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
void printer(int i) {
cout << i << ", ";
}
int main() {
int mynumbers[] = { 1, 2, 3, 4 };
vector<int> v(mynumbers, mynumbers + 4);
for_each(v.begin(), v.end(), negate<int>());//no effect as returned value of UnaryFunction negate() is ignored.
for_each(v.begin(), v.end(), printer); //guarantees order
cout << endl;
transform(v.begin(), v.end(), v.begin(), negate<int>());//negates elements correctly
for_each(v.begin(), v.end(), printer);
return 0;
}
which will print:
1, 2, 3, 4,
-1, -2, -3, -4,
Real example of using std::tranform is when you want to convert a string to uppercase, you can write code like this :
std::transform(s.begin(), s.end(), std::back_inserter(out), ::toupper);
if you will try to achieve same thing with std::for_each like :
std::for_each(s.begin(), s.end(), ::toupper);
It wont convert it into uppercase string
An std::map<K,V> m, in a mathematical view, is a function fm in which all pairs of domain and range elements (x,y) ∈ K × V such that fm(x) = y.
So, I want to get the domain of fm, i.e. the set of all keys (or perhaps the range - the set of all values). I can do this procedurally with C++11, like so:
std::unordered_set<K> keys;
for (const auto& kv_pair : m) { keys.insert(kv_pair->first); }
right? But - I want to do it functionally (read: In a fancy way which makes me feel superior). How would I do that?
Notes:
I do not necessarily need the result to be an std::unordered_set; something which would could replace such a set would probably work too (e.g. a set Facade).
Readability, (reasonable) terseness and avoiding gratuitous copying of data are all considerations.
Boost.Range provides exactly that, with the adaptor map_keys. Look at this example from the documentation.
You can write:
auto keys = m | boost::adaptors::map_keys;
// keys is a range view to the keys in your map, no copy involved
// you can use keys.begin() and keys.end() to iterate over it
EDIT : I'll leave my old answer below, it uses iterators instead of ranges. Notice that
the range represented by the two boost::transform_iterator still represents the set of keys in your map.
IMO the functional way to do that would require an iterator that points to the keys of the map, so that you can simply use std::copy.
It makes sense because you are not transforming or accumulating anything, you are just copying the keys.
Unfortunately the standard does not provide iterator adaptors, but you can use those provided by Boost.Iterator.
#include <algorithm>
#include <map>
#include <unordered_set>
#include <boost/iterator/transform_iterator.hpp>
struct get_first
{
template<class A, class B>
const A & operator()(const std::pair<A,B> & val) const
{
return val.first;
}
};
int main()
{
std::map<int, std::string> m;
std::unordered_set<int> r;
// ...
std::copy(boost::make_transform_iterator(m.begin(), get_first{}),
boost::make_transform_iterator(m.end(), get_first{}),
std::inserter(r, r.end()) );
}
It would be more expressive to have an iterator that dereferences the Kth element of a tuple/pair, but transform_iterator will do the job fine.
IMHO, an important characteristic for intuitive functional code is that the algorithm actually return the result, rather than setting some variable elsewhere as a side effect. This can be done with std::accumulate, e.g.:
#include <iostream>
#include <set>
#include <map>
#include <algorithm>
int main()
{
typedef std::map<int, int> M;
M m { {1, -1}, {2, -2}, {3, -3}, {4, -4} };
auto&& x = std::accumulate(std::begin(m), std::end(m), std::set<int>{},
[](std::set<int>& s, const M::value_type& e)
{
return s.insert(e.first), std::move(s);
// .first is key,
}); // .second is value
for (auto& i : x)
std::cout << i << ' ';
std::cout << '\n';
}
Output:
1 2 3 4
See it run here
The std::begin(m), std::end(m) bit is actually a big headache, as it frustrates chaining of such operations. For example, it's be ideal if we could chain "functional" operations like our "GET KEYS" above alongside others...
x = m. GET KEYS . SQUARE THEM ALL . REMOVE THE ODD ONES
...or at least...
x = f(f(f(m, GET KEYS), SQUARE THEM ALL), REMOVE THE ODD ONES)
...but you'll have to write some trivial code yourself to get there or pick up a library supporting functional "style".
There's a number of ways you could write this. One slightly more 'functional' way is:
vector<string> keys;
transform(begin(m), end(m), back_inserter(keys), [](const auto& p){ return p.first; });
But to really improve on this and enable a more functional style using the standard library we need something like Eric Niebler's Range Proposal to be standardized. In the meantime, there are a number of non-standard range based libraries like Eric's range-v3 and boost Range you can use to get a more functional style.
std::map<int, int> m;
std::unordered_set<int> keys;
std::for_each(m.begin(), m.end(), [&keys](decltype(*m.begin()) kv)-> void {keys.insert(kv.first);});