for_each - stl c++ reference
std:: copia n elementos o hasta el final (4)
Me gustaría copiar hasta N elementos.
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;
}
¿Hay una manera de hacer esto con funciones estándar? También podría:
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);
}
sin embargo, además de ser engorroso, va más allá del rango dos veces (distancia, copia). Si estoy usando un iterador de transformación o un filtro iterador, esas son llamadas innecesarias O (N) a mi función de filtro / transformación.
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 << " ,";
}
salidas 1,2,3,4,5,6,7,8,9,
sin embargo, esto continuará hasta el final, y no contará los tiempos. aún así, más llamadas innecesarias a mi filtro / función de transformación ...
Hay una forma sencilla de usar la std::copy_if
agregada por C ++ 11 para su tarea (solo necesita InputIterators):
template< class InputIt, class Size, class OutputIt>
OutputIt myCopy_n(InputIt first, InputIt last, Size count, OutputIt result)
{
return std::copy_if(first, last, result,
[&](typename std::iterator_traits<InputIt>::reference)
{return count && count--;});
}
Por cierto: se pone aún mejor en C ++ 14, sin necesidad de una variable o un argumento tan complicado:
std::copy_if(first, last, result,
[count = some_complicated_expression](auto&&) mutable
{return count && count--;});
Iría por algo como esto:
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;
});
}
Usando el predicado copy_if
para verificar si se copió o no suficiente de esta entrada. La principal ventaja que veo aquí es que no hay extra std::distance
involucrada.
Puede usar copy_if
con un predicador personalizado, y funciona para versiones anteriores de c ++.
#include <algorithm>
#include <iostream>
#include <vector>
#include <iterator>
struct LimitTo
{
LimitTo( const int n_ ) : n(n_)
{}
template< typename T >
bool operator()( const T& )
{
return n-->0;
}
int n;
};
int main()
{
std::vector< int > v1{ 1,2,3,4,5,6,7,8 };
std::vector< int > v2;
std::copy_if( std::begin(v1), std::end(v1), std::back_inserter(v2), LimitTo(3) );
std::copy( std::begin(v1), std::end(v1), std::ostream_iterator<int>(std::cout,", ") );
std::cout << std::endl;
std::copy( std::begin(v2), std::end(v2), std::ostream_iterator<int>(std::cout,", ") );
std::cout << std::endl;
}
Este ejemplo copia n elementos, utilizando el predicador LimitTo
.
Si tiene acceso a toda la estructura de datos y, por lo tanto, a su tamaño, puede usar lo siguiente:
std::vector<int> v1, v2;
std::copy_n(v2.begin(), std::min(NUM, v2.size()), std::back_inserter(v1));
Si solo tiene acceso a los iteradores, no sé cómo hacerlo utilizando solo las funciones estándar sin calcular la distancia. Esto es barato para los iteradores de acceso aleatorio, pero los duplicados funcionan para otros tipos.
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);