Iterating over more than one seq. container in C++11 - c++

I need a piece of advice for the following situation - I can't figure it out for hours:
How to walk through more than one seq . containers of same size (here: two vectors) in a simple way?
int main() {
int size = 3;
std::vector<int> v1{ 1, 2, 3 }, v2{ 6, 4, 2 };
// old-fashioned - ok
for (int i = 0; i < size; i++) {
std::cout << v1[i] << " " << v2[i] << std::endl;
}
// would like to do the same as above with auto range-for loop
// something like this - which would be fine for ONE vector.
// But this does not work. Do I need a hand-made iterator instead?
for (const auto& i:v1,v2) {
std::cout << i << " " << i << std::endl;
}
return EXIT_SUCCESS;
}
Thank you!

There is boost::combine() in Boost.Range that allows one to write
#include <iostream>
#include <iterator>
#include <vector>
#include <boost/range/combine.hpp>
int main()
{
std::vector<int> v1{ 1, 2, 3 }, v2{ 6, 4, 2 };
for (auto&& t : boost::combine(v1, v2))
std::cout << t.get<0>() << " " << t.get<1>() << "\n";
}
Live Example.
If you don't like to rely on this, you can spell out the combine() functionality yourself with Boost.Iterator's zip_iterator and Boost.Range's iterator_range and a little bit of C++14 deduced return-types:
template<class... Ranges>
auto combine(Ranges const&... ranges)
// add -> decltype( boost::make_iterator_range(...) ) in C++11
{
return boost::make_iterator_range(
boost::make_zip_iterator(boost::make_tuple(begin(ranges)...)),
boost::make_zip_iterator(boost::make_tuple(end(ranges)...))
);
}
Live Example.
Explanation: boost::make_zip_iterator creates a boost::tuple of iterators into your input ranges, and overloads all the usual operator++ and operator* that you know and love from regular iterators. The iterator_range then wraps two of these zip_iterators into a package with a begin() and end() function that allows it to be used by the C++11 range-for loop. It generalizes to more than two input ranges as well. You can unpack the K-th element from a tuple with the .get<K> member function.

The range-based for loop was designed as a convenience for iterating one range, because it's by far the most common case. If you need to iterate multiple ranges, which is not that most common case, you can still do it the traditional way:
for (auto i1 = begin(v1), i2 = begin(v2), e = end(v1); i1 != e; ++i1, ++i2)
{
// processing
}

Related

Iterating over odd (even) elements only in a range-based loop

Suppose we have a plain array (or other container which supports range-based loops):
const int N = 8;
int arr[N] = {0, 1, 2, 3, 4, 5, 6, 7};
Using indexes or iterators, we can loop over odd elements and increment the index by two:
for (int i = 0; i < N; i+=2)
{
std::cout << arr[i] << std::endl;
}
How can I get a similar result by using a range-based loop and avoiding explicit iterators/indexes and iteration skipping? Something like this:
for (const auto& v: odd_only(arr))
{
std::cout << v << std::endl;
}
What does a simple and elegant solution look like? Does the standard library contain something like this?
There's no support for what you request – but you might write your own even_only and odd_only implementations.
Basic idea is to wrap around the normal iterator of the container in question and do a double increment internally each time we increment once externally:
template <typename C, bool IsOdd>
class even_odd_only
{
C& c;
public:
class iterator
{
public:
// all the definitions required for iterator!
// most if not all might simply be derived from C::iterator...
// copy/move constructor/assignment as needed
// core of the wrapper: increment twice internally!
// just doing += 2 is dangerous, though, we might increment beyond
// the end iterator (undefined behaviour!)additionally, += 2 only
// is possible for random access iterators (so we limit usability)
void operator++() { ++b; if(b != e) ++b; }
// operator* and operator-> (both return *b), post-increment
// (defined in terms of pre-increment), etc...
// comparison: only needs to compare b iterators!
private:
C::iterator b;
C::iterator e; // needed for comparison to avoid incrementing beyond!
iterator(C::iterator b, C::iterator e) : b(b), e(e) { }
};
// const_iterator, too; possibly make a template of above
// and derive const and non-const iterators from?
even_odd_only(C& c) : c(c) { }
iterator begin()
{
using std::begin;
using std::end;
using std::empty;
auto b = begin(c);
// should be self-explanatory:
// skip first element in odd variant (if there is)
if constexpr(IsOdd) { if(!empty(c)) { ++b; } }
return iterator(b, end(c));
};
iterator end()
{
using std::end;
return iterator(end(c), end(c));
}
};
template <typename T>
using even_only = even_odd_base<T, false>;
template <typename T>
using odd_only = even_odd_base<T, true>;
As is, it would work even with non-random-access and even non-bidirectional iterators. But especially for RA-iterators, it's less efficient than the classic loop (due to the intermediate if in operator++).
Defining comparison iterators: always operator== and operator!=, only for random access operators you can additionally have operator[<|>|<=|>=] (→ std::enable_if).
You'll find more details about how to write an iterator here – keep in mind when you encounter, though, that std::iterator itself is deprecated now.
As for what you are currently asking; I do not believe anything exists yet. Now as for iterating over a container by some integer N we can do the following; we can write our own for_each type of function. I've written one below and it works like a gem! You may also want to look into the std::advance function as well for it can be another possible implementation. I was checking that out myself as I was writing this function. However; as for c arrays I'm not sure there is much one can do without a bunch of extra code such as class templates, wrappers, etc. Here is my function.
#include <array>
#include <vector>
#include <iterator>
template<typename Container, typename Function>
void for_each_by_n( Container&& cont, Function f, unsigned increment_by = 1) {
if ( increment_by == 0 ) return; // must check this for no op
using std::begin;
auto it = begin(cont);
using std::end;
auto end_it = end(cont);
while( it != end_it ) {
f(*it);
for ( unsigned n = 0; n < increment_by; ++n ) {
if ( it == end_it ) return;
++it;
}
}
}
int main() {
std::array<int,8> arr{ 0,1,2,3,4,5,6,7 };
std::vector<double> vec{ 1.2, 1.5, 1.9, 2.5, 3.3, 3.7, 4.2, 4.8 };
auto l = [](auto& v) { std::cout << v << ' '; };
for_each_by_n(arr, l); std::cout << '\n';
for_each_by_n(vec, l); std::cout << '\n';
for_each_by_n(arr, l, 2); std::cout << '\n';
for_each_by_n(arr, l, 4); std::cout << '\n';
for_each_by_n(vec, l, 3); std::cout << '\n';
for_each_by_n(vec, l, 5); std::cout << '\n';
for_each_by_n(arr, l, 8); std::cout << '\n';
for_each_by_n(vec, l, 8); std::cout << '\n';
// sanity check to see if it doesn't go past end.
for_each_by_n(arr, l, 9); std::cout << '\n';
for_each_by_n(vec, l, 9); std::cout << '\n';
return 0;
}
-Output-
0 1 2 3 4 5 6 7
1.2 1.5 1.9 2.5 3.3 3.7 4.2 4.8
0 2 4 6
0 4
1.2 2.5 4.2
1.2 3.7
0
1.2
0
1.2
What I like about this example above is that not only can you increment through a loop by some integer N; the above function also takes a function pointer, function object, functor, or lambda and it will perform the required action.
In your case you was trying to loop through your container by 2 for ever odd or every even index and within the loop you were printing the results. Here in my example; I'm printing the results in the form of a lambda that is being passed to this function.
However the only caveat with this particular implementation is that it will always start from index 0. You could easily expand on this by introducing another integer parameter as to an offset of where the iteration will begin; but I'll leave that up to you to do as an exercise.
For the time being we have to settle for what C++11 through C++17 has to offer. In the near future we should have many new and powerful features with the release of C++20.
There is a ready-made solution for this problem in the Range-v3. I think this can be useful if you don’t want to write your own implementation or need more flexibility (f.e. arbitrary stride)
#include <range/v3/all.hpp>
void example()
{
int data[8] = {0, 1, 2, 3, 4, 5, 6, 7};
for (auto i : ranges::view::stride(data, 2))
{
std::cout << i << std::endl;
}
}
(copied from #hlt comment)
This isn't really an answer to the question, but—for what it is worth—whenever I run into a limitation of ranged-for, I look for a standard algorithm solution. Like...
#include <algorithm>
#include <iostream>
#include <iterator>
#include <utility>
int main()
{
int arr[] {0, 1, 2, 3, 4, 5, 6, 7};
std::copy_if(
std::begin(arr), std::end(arr),
std::ostream_iterator<int>(std::cout, "\n"),
[is_odd_element = true](int n) mutable {
return std::exchange(is_odd_element, not is_odd_element);
});
}

What's a good implementation of applying a unary function to some elements of a vector?

I'd like to apply a function UnaryFunction f to some elements of a std container, given a predicate UnaryPredicate p - sort of what you would get if you combine std::partition and then apply std::for_each to one of the partitions.
I'm quite new to C++, so forgive my ignorance. I have, however, looked for a suitable implementation in <algorithm>, yet I can't seem to find the desired function.
Based on the possible implementations over at cppreference.com, I've come up with the following:
template<class InputIt, class UnaryPredicate, class UnaryFunction>
UnaryFunction for_each_if(InputIt first, InputIt last, UnaryPredicate p, UnaryFunction f)
{
for (; first != last; ++first) {
if (p(*first))
{
f(*first);
}
}
return f;
}
The return value is modeled as per std::for_each, although an OutputIter might have been a better choice. This would require a more convoluted implementation though, and so I've chosen brevity over finesse this time around. The alternative implementation is left as an exercise to the reader.
My question is: is there already an established way to do this in the std library? If not, would this be a reasonable implementation of such a function template?
STL does not support composition of algorithms very well. As you said, you could first call partition, and then call for_each on one of the partitions if you don't care about the order of elements.
For a new project, or one where you can introduce libraries, I would strongly recommend to have a look at a range library, e.g. Boost.Range or Eric Niebler's range-v3.
With the range library, it can be done like this:
template<typename R, typename P, typename F>
F for_each_if(R& rng, P pred, F f)
{
using namespace boost::adaptors;
return (rng | filtered(pred) | for_each(f));
}
As far as the comments go, there seems to be no implementation of this in the std library. However, as user2672165 points out, the predicate may be easily included in the function. To illustrate this, see the following modified version of the for_each example over at cppreference.com:
#include <vector>
#include <algorithm>
#include <iostream>
struct Sum {
Sum() { sum = 0; }
void operator()(int n) { sum += n; }
int sum;
};
int main()
{
std::vector<int> nums{3, 4, 2, 9, 15, 267};
std::cout << "before: ";
for (auto n : nums) {
std::cout << n << " ";
}
std::cout << '\n';
std::for_each(nums.begin(), nums.end(), [](int &n){ if (n > 5) n++; });
// Calls Sum::operator() for each number
Sum s = std::for_each(nums.begin(), nums.end(), Sum());
std::cout << "after: ";
for (auto n : nums) {
std::cout << n << " ";
}
std::cout << '\n';
std::cout << "sum: " << s.sum << '\n';
}
Here, the predicate is added to the function, so that [](int &n){ n++; } now becomes [](int &n){ if (n > 5) n++; } to only apply the function to integer elements greater than 5.
Expected output is
before: 3 4 2 9 15 267
after: 3 4 2 10 16 268
sum: 303
Hope this helps someone else out there.

Merging two lists efficiently with limited bound

I am trying to merge two arrays/lists where each element of the array has to be compared. If there is an identical element in both of them I increase their total occurrence by one. The arrays are both 2D, where each element has a counter for its occurrence. I know both of these arrays can be compared with a double for loop in O(n^2), however I am limited by a bound of O(nlogn). The final array will have all of the elements from both lists with their increased counters if there are more than one occurrence
Array A[][] = [[8,1],[5,1]]
Array B[][] = [[2,1],[8,1]]
After the merge is complete I should get an array like so
Array C[][] = [[2,1],[8,2],[8,2],[5,1]]
The arrangement of the elements does not have to be necessary.
From readings, Mergesort takes O(nlogn) to merge two lists however I am currently at a roadblock with my bound problem. Any pseudo code visual would be appreciated.
I quite like Stepanov's Efficient Programming although they are rather slow. In sessions 6 and 7 (if I recall correctly) he discusses the algorithms add_to_counter() and reduce_counter(). Both algorithms are entirely trivial, of course, but can be used to implement a non-recursive merge-sort without too much effort. The only possibly non-obvious insight is that the combining operation can reduce the two elements into a sequence rather than just one element. To do the operations in-place you'd actually store iterators (i.e., pointers in case of arrays) using a suitable class to represent a partial view of an array.
I haven't watched the sessions beyond session 7 (and actually not even the complete session 7, yet) but I would fully expect that he actually presents how to use the counter produced in session 7 to implement, e.g., merge-sort. Of course, the run-time complexity of merge-sort is O(n ln n) and, when using the counter approach it will use O(ln n) auxiliary space.
A simple algorithm that requires twice as much memory would be to order both inputs (O(n log n)) and then sequentially pick the elements from the head of both lists and do the merge (O(n)). The overall cost would be O(n log n) with O(n) extra memory (additional size of the smallest of both inputs)
Here's my algorithm based on bucket counting
time complexity: O(n)
memory complexity: O(max), where max is the maximum element in the arrays
Output:
[8,2][5,1][2,1][8,2]
Code:
#include <iostream>
#include <vector>
#include <iterator>
int &refreshCount(std::vector<int> &counters, int in) {
if((counters.size() - 1) < in) {
counters.resize(in + 1);
}
return ++counters[in];
}
void copyWithCounts(std::vector<std::pair<int, int> >::iterator it,
std::vector<std::pair<int, int> >::iterator end,
std::vector<int> &counters,
std::vector<std::pair<int, int&> > &result
) {
while(it != end) {
int &count = refreshCount(counters, (*it).first);
std::pair<int, int&> element((*it).first, count);
result.push_back(element);
++it;
}
}
void countingMerge(std::vector<std::pair<int, int> > &array1,
std::vector<std::pair<int, int> > &array2,
std::vector<std::pair<int, int&> > &result) {
auto array1It = array1.begin();
auto array1End = array1.end();
auto array2It = array2.begin();
auto array2End = array2.end();
std::vector<int> counters = {0};
copyWithCounts(array1It, array1End, counters, result);
copyWithCounts(array2It, array2End, counters, result);
}
int main()
{
std::vector<std::pair<int, int> > array1 = {{8, 1}, {5, 1}};
std::vector<std::pair<int, int> > array2 = {{2, 1}, {8, 1}};
std::vector<std::pair<int, int&> > result;
countingMerge(array1, array2, result);
for(auto it = result.begin(); it != result.end(); ++it) {
std::cout << "[" << (*it).first << "," << (*it).second << "] ";
}
return 0;
}
Short explanation:
because you mentioned, that final arrangement is not necessary, I did simple merge (without sort, who asked sort?) with counting, where result contains reference to counters, so no need to walk through the array to update the counters.
You could write an algorithm to merge them by walking both sequences sequentially in order, inserting where appropriate.
I've chosen a (seemingly more apt) datastructure here: std::map<Value, Occurence>:
#include <map>
using namespace std;
using Value = int;
using Occurence = unsigned;
using Histo = map<Value, Occurence>;
If you insist on contiguous storage, boost::flat_map<> should be your friend here (and a drop-in replacement).
The algorithm (tested with your inputs, read comments for explanation):
void MergeInto(Histo& target, Histo const& other)
{
auto left_it = begin(target), left_end = end(target);
auto right_it = begin(other), right_end = end(other);
auto const& cmp = target.value_comp();
while (right_it != right_end)
{
if ((left_it == left_end) || cmp(*right_it, *left_it))
{
// insert at left_it
target.insert(left_it, *right_it);
++right_it; // and carry on
} else if (cmp(*left_it, *right_it))
{
++left_it; // keep left_it first, so increment it
} else
{
// keys match!
left_it->second += right_it->second;
++left_it;
++right_it;
}
}
}
It's really quite straight-forward!
A test program: See it Live On Coliru
#include <iostream>
// for debug output
static inline std::ostream& operator<<(std::ostream& os, Histo::value_type const& v) { return os << "{" << v.first << "," << v.second << "}"; }
static inline std::ostream& operator<<(std::ostream& os, Histo const& v) { for (auto& el : v) os << el << " "; return os; }
//
int main(int argc, char *argv[])
{
Histo A { { 8, 1 }, { 5, 1 } };
Histo B { { 2, 1 }, { 8, 1 } };
std::cout << "A: " << A << "\n";
std::cout << "B: " << B << "\n";
MergeInto(A, B);
std::cout << "merged: " << A << "\n";
}
Printing:
A: {5,1} {8,1}
B: {2,1} {8,1}
merged: {2,1} {5,1} {8,2}
You could shuffle the interface a tiny bit in case you really wanted to merge into a new object (C):
// convenience
Histo Merge(Histo const& left, Histo const& right)
{
auto copy(left);
MergeInto(copy, right);
return copy;
}
Now you can just write
Histo A { { 8, 1 }, { 5, 1 } };
Histo B { { 2, 1 }, { 8, 1 } };
auto C = Merge(A, B);
See that Live on Coliru, too

How to find the index of current object in range-based for loop?

Assume I have the following code:
vector<int> list;
for(auto& elem:list) {
int i = elem;
}
Can I find the position of elem in the vector without maintaining a separate iterator?
Yes you can, it just take some massaging ;)
The trick is to use composition: instead of iterating over the container directly, you "zip" it with an index along the way.
Specialized zipper code:
template <typename T>
struct iterator_extractor { typedef typename T::iterator type; };
template <typename T>
struct iterator_extractor<T const> { typedef typename T::const_iterator type; };
template <typename T>
class Indexer {
public:
class iterator {
typedef typename iterator_extractor<T>::type inner_iterator;
typedef typename std::iterator_traits<inner_iterator>::reference inner_reference;
public:
typedef std::pair<size_t, inner_reference> reference;
iterator(inner_iterator it): _pos(0), _it(it) {}
reference operator*() const { return reference(_pos, *_it); }
iterator& operator++() { ++_pos; ++_it; return *this; }
iterator operator++(int) { iterator tmp(*this); ++*this; return tmp; }
bool operator==(iterator const& it) const { return _it == it._it; }
bool operator!=(iterator const& it) const { return !(*this == it); }
private:
size_t _pos;
inner_iterator _it;
};
Indexer(T& t): _container(t) {}
iterator begin() const { return iterator(_container.begin()); }
iterator end() const { return iterator(_container.end()); }
private:
T& _container;
}; // class Indexer
template <typename T>
Indexer<T> index(T& t) { return Indexer<T>(t); }
And using it:
#include <iostream>
#include <iterator>
#include <limits>
#include <vector>
// Zipper code here
int main() {
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto p: index(v)) {
std::cout << p.first << ": " << p.second << "\n";
}
}
You can see it at ideone, though it lacks the for-range loop support so it's less pretty.
EDIT:
Just remembered that I should check Boost.Range more often. Unfortunately no zip range, but I did found a pearl: boost::adaptors::indexed. However it requires access to the iterator to pull of the index. Shame :x
Otherwise with the counting_range and a generic zip I am sure it could be possible to do something interesting...
In the ideal world I would imagine:
int main() {
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto tuple: zip(iota(0), v)) {
std::cout << tuple.at<0>() << ": " << tuple.at<1>() << "\n";
}
}
With zip automatically creating a view as a range of tuples of references and iota(0) simply creating a "false" range that starts from 0 and just counts toward infinity (or well, the maximum of its type...).
jrok is right : range-based for loops are not designed for that purpose.
However, in your case it is possible to compute it using pointer arithmetic since vector stores its elements contiguously (*)
vector<int> list;
for(auto& elem:list) {
int i = elem;
int pos = &elem-&list[0]; // pos contains the position in the vector
// also a &-operator overload proof alternative (thanks to ildjarn) :
// int pos = addressof(elem)-addressof(list[0]);
}
But this is clearly a bad practice since it obfuscates the code & makes it more fragile (it easily breaks if someone changes the container type, overload the & operator or replace 'auto&' by 'auto'. good luck to debug that!)
NOTE: Contiguity is guaranteed for vector in C++03, and array and string in C++11 standard.
No, you can't (at least, not without effort). If you need the position of an element, you shouldn't use range-based for. Remember that it's just a convenience tool for the most common case: execute some code for each element. In the less-common circumstances where you need the position of the element, you have to use the less-convenient regular for loop.
Based on the answer from #Matthieu there is a very elegant solution using the mentioned boost::adaptors::indexed:
std::vector<std::string> strings{10, "Hello"};
int main(){
strings[5] = "World";
for(auto const& el: strings| boost::adaptors::indexed(0))
std::cout << el.index() << ": " << el.value() << std::endl;
}
You can try it
This works pretty much like the "ideal world solution" mentioned, has pretty syntax and is concise. Note that the type of el in this case is something like boost::foobar<const std::string&, int>, so it handles the reference there and no copying is performed. It is even incredibly efficient: https://godbolt.org/g/e4LMnJ (The code is equivalent to keeping an own counter variable which is as good as it gets)
For completeness the alternatives:
size_t i = 0;
for(auto const& el: strings) {
std::cout << i << ": " << el << std::endl;
++i;
}
Or using the contiguous property of a vector:
for(auto const& el: strings) {
size_t i = &el - &strings.front();
std::cout << i << ": " << el << std::endl;
}
The first generates the same code as the boost adapter version (optimal) and the last is 1 instruction longer: https://godbolt.org/g/nEG8f9
Note: If you only want to know, if you have the last element you can use:
for(auto const& el: strings) {
bool isLast = &el == &strings.back();
std::cout << isLast << ": " << el << std::endl;
}
This works for every standard container but auto&/auto const& must be used (same as above) but that is recommended anyway. Depending on the input this might also be pretty fast (especially when the compiler knows the size of your vector)
Replace the &foo by std::addressof(foo) to be on the safe side for generic code.
If you have a compiler with C++14 support you can do it in a functional style:
#include <iostream>
#include <string>
#include <vector>
#include <functional>
template<typename T>
void for_enum(T& container, std::function<void(int, typename T::value_type&)> op)
{
int idx = 0;
for(auto& value : container)
op(idx++, value);
}
int main()
{
std::vector<std::string> sv {"hi", "there"};
for_enum(sv, [](auto i, auto v) {
std::cout << i << " " << v << std::endl;
});
}
Works with clang 3.4 and gcc 4.9 (not with 4.8); for both need to set -std=c++1y. The reason you need c++14 is because of the auto parameters in the lambda function.
If you insist on using range based for, and to know index, it is pretty trivial to maintain index as shown below.
I do not think there is a cleaner / simpler solution for range based for loops. But really why not use a standard for(;;)? That probably would make your intent and code the clearest.
vector<int> list;
int idx = 0;
for(auto& elem:list) {
int i = elem;
//TODO whatever made you want the idx
++idx;
}
There is a surprisingly simple way to do this
vector<int> list;
for(auto& elem:list) {
int i = (&elem-&*(list.begin()));
}
where i will be your required index.
This takes advantage of the fact that C++ vectors are always contiguous.
Here's a quite beautiful solution using c++20:
#include <array>
#include <iostream>
#include <ranges>
template<typename T>
struct EnumeratedElement {
std::size_t index;
T& element;
};
auto enumerate(std::ranges::range auto& range)
-> std::ranges::view auto
{
return range | std::views::transform(
[i = std::size_t{}](auto& element) mutable {
return EnumeratedElement{i++, element};
}
);
}
auto main() -> int {
auto const elements = std::array{3, 1, 4, 1, 5, 9, 2};
for (auto const [index, element] : enumerate(elements)) {
std::cout << "Element " << index << ": " << element << '\n';
}
}
The major features used here are c++20 ranges, c++20 concepts, c++11 mutable lambdas, c++14 lambda capture initializers, and c++17 structured bindings. Refer to cppreference.com for information on any of these topics.
Note that element in the structured binding is in fact a reference and not a copy of the element (not that it matters here). This is because any qualifiers around the auto only affect a temporary object that the fields are extracted from, and not the fields themselves.
The generated code is identical to the code generated by this (at least by gcc 10.2):
#include <array>
#include <iostream>
#include <ranges>
auto main() -> int {
auto const elements = std::array{3, 1, 4, 1, 5, 9, 2};
for (auto index = std::size_t{}; auto& element : elements) {
std::cout << "Element " << index << ": " << element << '\n';
index++;
}
}
Proof: https://godbolt.org/z/a5bfxz
I read from your comments that one reason you want to know the index is to know if the element is the first/last in the sequence. If so, you can do
for(auto& elem:list) {
// loop code ...
if(&elem == &*std::begin(list)){ ... special code for first element ... }
if(&elem == &*std::prev(std::end(list))){ ... special code for last element ... }
// if(&elem == &*std::rbegin(list)){... (C++14 only) special code for last element ...}
// loop code ...
}
EDIT: For example, this prints a container skipping a separator in the last element. Works for most containers I can imagine (including arrays), (online demo http://coliru.stacked-crooked.com/a/9bdce059abd87f91):
#include <iostream>
#include <vector>
#include <list>
#include <set>
using namespace std;
template<class Container>
void print(Container const& c){
for(auto& x:c){
std::cout << x;
if(&x != &*std::prev(std::end(c))) std::cout << ", "; // special code for last element
}
std::cout << std::endl;
}
int main() {
std::vector<double> v{1.,2.,3.};
print(v); // prints 1,2,3
std::list<double> l{1.,2.,3.};
print(l); // prints 1,2,3
std::initializer_list<double> i{1.,2.,3.};
print(i); // prints 1,2,3
std::set<double> s{1.,2.,3.};
print(s); // print 1,2,3
double a[3] = {1.,2.,3.}; // works for C-arrays as well
print(a); // print 1,2,3
}
Tobias Widlund wrote a nice MIT licensed Python style header only enumerate (C++17 though):
GitHub
Blog Post
Really nice to use:
std::vector<int> my_vector {1,3,3,7};
for(auto [i, my_element] : en::enumerate(my_vector))
{
// do stuff
}
If you want to avoid having to write an auxiliary function while having
the index variable local to the loop, you can use a lambda with a mutable variable.:
int main() {
std::vector<char> values = {'a', 'b', 'c'};
std::for_each(begin(values), end(values), [i = size_t{}] (auto x) mutable {
std::cout << i << ' ' << x << '\n';
++i;
});
}
Here's a macro-based solution that probably beats most others on simplicity, compile time, and code generation quality:
#include <iostream>
#define fori(i, ...) if(size_t i = -1) for(__VA_ARGS__) if(i++, true)
int main() {
fori(i, auto const & x : {"hello", "world", "!"}) {
std::cout << i << " " << x << std::endl;
}
}
Result:
$ g++ -o enumerate enumerate.cpp -std=c++11 && ./enumerate
0 hello
1 world
2 !

Calling a function on every element of a C++ vector

In C++, is there a way to call a function on each element of a vector, without using a loop running over all vector elements? Something similar to a 'map' in Python.
You've already gotten several answers mentioning std::for_each.
While these respond to the question you've asked, I'd add that at least in my experience, std::for_each is about the least useful of the standard algorithms.
I use (for one example) std::transform, which is basically a[i] = f(b[i]); or result[i] = f(a[i], b[i]); much more frequently than std::for_each. Many people frequently use std::for_each to print elements of a collection; for that purpose, std::copy with an std::ostream_iterator as the destination works much better.
Yes: std::for_each.
#include <algorithm> //std::for_each
void foo(int a) {
std::cout << a << "\n";
}
std::vector<int> v;
...
std::for_each(v.begin(), v.end(), &foo);
On C++ 11: You could use a lambda. For example:
std::vector<int> nums{3, 4, 2, 9, 15, 267};
std::for_each(nums.begin(), nums.end(), [](int &n){ n++; });
ref: http://en.cppreference.com/w/cpp/algorithm/for_each
If you have C++11, there's an even shorter method: ranged-based for. Its purpose is exactly this.
std::vector<int> v {1,2,3,4,5};
for (int element : v)
std::cout << element; //prints 12345
You can also apply references and const to it as well, when appropriate, or use auto when the type is long.
std::vector<std::vector<int>> v {{1,2,3},{4,5,6}};
for (const auto &vec : v)
{
for (int element : vec)
cout << element;
cout << '\n';
}
Output:
123
456
The OP mentions the map function in Python.
This Python function actually applies a function to every element of a list (or iterable) and returns a list (or iterable) that collects all results.
In other words, it does something like this:
def f( x ) :
""" a function that computes something with x"""
# code here
return y
input = [ x1, x2, x3, ... ]
output = map( func, input )
# output is now [ f(x1), f(x2), f(x3), ...]
Hence, the closest C++ standard-library equivalent to Python's map is actually std::transform (from the <algorithm> header).
Example usage is as follows:
#include <vector>
#include <algorithm>
using namespace std;
double f( int x ) {
// a function that computes the square of x divided by 2.0
return x * x / 2.0 ;
}
int main( ) {
vector<int> input{ 1, 5, 10 , 20};
vector<double> output;
output.resize( input.size() ); // unfortunately this is necessary
std::transform( input.begin(), input.end(), output.begin(), f );
// output now contains { f(1), f(5), f(10), f(20) }
// = { 0.5, 12.5, 50.0, 200.0 }
return 0;
}
Use for_each:
// for_each example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void myfunction (int i) {
cout << " " << i;
}
struct myclass {
void operator() (int i) {cout << " " << i;}
} myobject;
int main () {
vector<int> myvector;
myvector.push_back(10);
myvector.push_back(20);
myvector.push_back(30);
cout << "myvector contains:";
for_each (myvector.begin(), myvector.end(), myfunction);
// or:
cout << "\nmyvector contains:";
for_each (myvector.begin(), myvector.end(), myobject);
cout << endl;
return 0;
}
You can use std::for_each which takes a pair of iterators and a function or functor.
Thought I would share std::ranges equivalents for for_each and transform, should anyone prefer them:
std::vector<int> v;
std::ranges::for_each(v,[](const auto& n) {});
const auto squared = v | std::views::transform([](const auto& n) { return n*2; });
Running on godbolt: https://godbolt.org/z/zYME6b