Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::copy n elements or to the end

Tags:

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...

like image 682
aivision2020 Avatar asked Sep 30 '14 11:09

aivision2020


2 Answers

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); 
like image 132
Neil Kirk Avatar answered Oct 26 '22 20:10

Neil Kirk


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

like image 21
Johan Avatar answered Oct 26 '22 19:10

Johan