I would like to copy up to N elements.
template< class InputIt, class Size, class OutputIt> OutputIt myCopy_n(InputIt first, InputIt last, Size count, OutputIt result) { Size c = count; while (first != last && c > 0) { *result++ = *first++; --c; } return result; }
is there a way to do this with std functions? I could also:
template< class InputIt, class Size, class OutputIt> OutputIt myCopy_n(InputIt first, InputIt last, Size count, OutputIt result) { if(std::distance(first, last) > count) return std::copy_n(first,count,result); return std::copy(first,last,result); }
however, besides being cumbersome, it goes over the range twice (distance, copy). If i'm using a transform iterator, or filter iterator, those are O(N) unnecessary calls to my filter/transform function.
template <class InputIt, class OutputIt> OutputIt copy_n_max(InputIt begin, InputIt end, OutputIt last, size_t count) { return std::copy_if(begin, end, last, [&count](typename std::iterator_traits<InputIt>::reference) { return count--> 0; }); } int main() { std::vector<int> v({1,2,3,4,5,6,7,8,9}), out; copy_n_max(v.begin(), v.end(), std::back_inserter(out), 40); for(int i : out) std::cout <<i << " ,"; }
outputs 1,2,3,4,5,6,7,8,9,
however, this will continue until end, and not count times. so still, more unnecessary calls to my filter/transform function...
If you have access to the whole data structure, and therefore its size, you can use the following:
std::vector<int> v1, v2; std::copy_n(v2.begin(), std::min(NUM, v2.size()), std::back_inserter(v1));
If you have access to only iterators, I don't know how to do this using only std functions without calculating the distance. This is cheap for random-access iterators but duplicates work for other types.
std::vector<int>::iterator i_begin, i_end, o_begin; std::copy_n(i_begin, std::min(NUM, std::distance(i_begin, i_end)), o_begin);
I would go for something like this:
template <class InputIt, class OutputIt> OutputIt copy_n_max(InputIt begin, InputIt end, OutputIt last, size_t count) { return std::copy_if(begin, end, last, [&count](typename std::iterator_traits<InputIt>::reference) -> bool { if (count > 0) { --count; return true; } return false; }); }
Using copy_if
predicate to check whether or not enough of this input was copied. Main advantage I see here is no extra std::distance
involved.
Live example on IDEOne
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With