programacion - tipos de arreglos en c++
usando STL para encontrar todos los elementos en un vector (7)
Tengo una colección de elementos sobre los que necesito operar, llamando funciones miembro en la colección:
std::vector<MyType> v;
... // vector is populated
Para las funciones de llamada sin argumentos es bastante directo:
std::for_each(v.begin(), v.end(), std::mem_fun(&MyType::myfunc));
Algo similar se puede hacer si hay un argumento para la función a la que deseo llamar.
Mi problema es que quiero llamar a una función en elementos en el vector si cumple alguna condición. std::find_if
devuelve un iterador al primer elemento que cumple las condiciones del predicado.
std::vector<MyType>::iterator it =
std::find_if(v.begin(), v.end(), MyPred());
Deseo encontrar todos los elementos que cumplan con el predicado y operar sobre ellos.
He estado buscando en los algoritmos STL un find_all
" find_all
" o " do_if
", o una forma en que puedo hacer esto con el STL existente (de modo que solo necesito iterar una vez), en lugar de hacer el mío o simplemente hacer una iteración estándar usando un bucle for y comparaciones.
Funciones de Lamda: la idea es hacer algo como esto
for_each(v.begin(), v.end(), [](MyType& x){ if (Check(x) DoSuff(x); })
Publicación origial aquí .
Por lo que su valor para_each_if se está considerando como una eventual adición para impulsar. No es difícil implementar el tuyo.
Puedes usar Boost.Foreach :
BOOST_FOREACH (vector<...>& x, v)
{
if (Check(x)
DoStuff(x);
}
Boost Lambda lo hace fácil.
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/if.hpp>
std::for_each( v.begin(), v.end(),
if_( MyPred() )[ std::mem_fun(&MyType::myfunc) ]
);
Incluso podría eliminar la definición de MyPred (), si es simple. Aquí es donde realmente brilla lambda. Por ejemplo, si MyPred significaba "es divisible por 2":
std::for_each( v.begin(), v.end(),
if_( _1 % 2 == 0 )[ std::mem_fun( &MyType::myfunc ) ]
);
Actualización: Hacer esto con la sintaxis lambda C ++ 0x también es muy agradable (continuando con el predicado como módulo 2):
std::for_each( v.begin(), v.end(),
[](MyType& mt ) mutable
{
if( mt % 2 == 0)
{
mt.myfunc();
}
} );
A primera vista, esto parece un paso atrás de la sintaxis de boost :: lambda, sin embargo, es mejor porque la lógica de functor más compleja es trivial de implementar con la sintaxis de c ++ 0x ... donde cualquier cosa muy complicada en boost :: lambda se vuelve difícil con rapidez. Microsoft Visual Studio 2010 beta 2 actualmente implementa esta funcionalidad.
std::vector<int> v, matches;
std::vector<int>::iterator i = v.begin();
MyPred my_pred;
while(true) {
i = std::find_if(i, v.end(), my_pred);
if (i == v.end())
break;
matches.push_back(*i);
}
Para el registro, aunque he visto una implementación donde llamar a end()
en una list
era O (n), no he visto ninguna implementación de STL donde la llamada a end()
en un vector
fuera diferente de O (1) - principalmente porque se garantiza que los vector
tienen iteradores de acceso aleatorio.
Aun así, si le preocupa un end()
ineficiente end()
, puede usar este código:
std::vector<int> v, matches;
std::vector<int>::iterator i = v.begin(), end = v.end();
MyPred my_pred;
while(true) {
i = std::find_if(i, v.end(), my_pred);
if (i == end)
break;
matches.push_back(*i);
}
¿Está bien cambiar el vector? Es posible que desee ver el algoritmo de partición.
Algoritmo de partición
Otra opción sería cambiar su MyType::myfunc
para verificar el elemento, o tomar un predicado como parámetro y usarlo para probar el elemento en el que está operando.
Escribí un for_each_if()
y un for_each_equal()
que hacen lo que creo que estás buscando.
for_each_if()
toma un functor de predicado para evaluar la igualdad, y for_each_equal()
toma un valor de cualquier tipo y hace una comparación directa usando operator ==
. En ambos casos, la función que pasa se invoca en cada elemento que pasa la prueba de igualdad.
/* ---
For each
25.1.1
template< class InputIterator, class Function, class T>
Function for_each_equal(InputIterator first, InputIterator last, const T& value, Function f)
template< class InputIterator, class Function, class Predicate >
Function for_each_if(InputIterator first, InputIterator last, Predicate pred, Function f)
Requires:
T is of type EqualityComparable (20.1.1)
Effects:
Applies f to each dereferenced iterator i in the range [first, last) where one of the following conditions hold:
1: *i == value
2: pred(*i) != false
Returns:
f
Complexity:
At most last - first applications of f
--- */
template< class InputIterator, class Function, class Predicate >
Function for_each_if(InputIterator first,
InputIterator last,
Predicate pred,
Function f)
{
for( ; first != last; ++first)
{
if( pred(*first) )
f(*first);
}
return f;
};
template< class InputIterator, class Function, class T>
Function for_each_equal(InputIterator first,
InputIterator last,
const T& value,
Function f)
{
for( ; first != last; ++first)
{
if( *first == value )
f(*first);
}
return f;
};