c++ - vectorizados - vectores gratis illustrator
C++ std:: transformar vector de pares-> primero a nuevo vector (6)
Perdón por una pequeña pregunta para principiantes. Hay vectores y vectores de pares.
typedef std::vector <int> TItems;
typedef std::vector < std::pair <int, int> > TPairs;
¿Hay alguna manera de transformar todos los primeros artículos en par a otro vector en un solo paso?
int main ()
{
TItems items;
TPairs pairs;
pairs.push_back (std::make_pair(1,3));
pairs.push_back (std::make_pair(5,7));
std::transform( items.begin(), items.end(), items.begin(), comp ( &pairs ) );
return 0;
}
¿Cómo diseñar un funtor?
class comp
{
private:
TPairs *pairs;
public:
comp ( TPairs *pairs_ ) : pairs ( pairs_) { }
unsigned int operator () ( const unsigned int index ) const
{
return (*pairs)[index].second != pairs->end(); //Bad idea
}
};
Tal vez exista un método más fácil de usar sin expresiones lambda y bucles. Gracias por tu ayuda.
¡Realmente quiero que uses std::get
como el funtor, porque ya se proporciona como una función de biblioteca!
¿No sería genial si pudiéramos escribir esta línea?
std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>);
... Pero es un poco más terrible que eso. Necesitas desmarcar los que usas:
int main() {
std::vector<int> items;
std::vector<std::pair<int, int>> pairs;
pairs.push_back(std::make_pair(1, 3));
pairs.push_back(std::make_pair(5, 7));
std::transform(pairs.begin(), pairs.end(), std::back_inserter(items),
(const int& (*)(const std::pair<int, int>&))std::get<0>);
return 0;
}
El problema es que std::get
está sobrecargado para tomar 1. pair&
, 2. const pair&
, y 3. pair&&
como parámetros, de modo que funcione para cualquier tipo de par como entrada. Desafortunadamente, las sobrecargas impiden la deducción del tipo de plantilla para std::transform
, por lo que nuestra línea original
std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>);
rendimientos
error: no matching function for call to ‘transform(std::vector<std::pair<int, int> >::iterator, std::vector<std::pair<int, int> >::iterator, std::back_insert_iterator<std::vector<int> >, <unresolved overloaded function type>)’
std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>);
^
...
/usr/include/c++/4.8/bits/stl_algo.h:4915:5: note: template argument deduction/substitution failed:
note: couldn''t deduce template parameter ‘_UnaryOperation’
std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>);
No sabe qué sobrecarga de std::get
está solicitando al deducir la plantilla para std::transform
, por lo que debe especificarla manualmente. Convertir el puntero de función al tipo correcto le dice al compilador, "Oye, usa la sobrecarga donde get
toma una const&
y devuelve una const&
!"
¿Pero al menos estamos usando componentes de biblioteca estándar (yay)?
Y en términos de número de líneas, no es peor que las otras opciones: http://ideone.com/6dfzxz
¿Qué hay de usar std::bind
?
std::transform(pairs.begin(),
pairs.end(),
std::back_inserter(items),
std::bind(&TPairs::value_type::first, std::placeholders::_1));
(Reemplace std::bind
por boost::bind
para código que no sea C ++ 11)
¿Qué tal esto?
items.reserve(pairs.size());
for (size_t it = 0; it < pairs.size(); ++it) {
items.push_back(pairs[it].first);
}
Simple de entender y depurar.
En primer lugar, debe usar un back_inserter
como tercer argumento para transform
modo que los valores transformados se inserten en la parte posterior del vector.
Segundo, necesitas algún tipo de functor que toma un par de entradas y devuelve el primero. Esto debería hacer:
int firstElement( const std::pair<int, int> &p ) {
return p.first;
}
Ahora, para juntar las piezas:
TPairs pairs;
pairs.push_back( std::make_pair( 1, 3 ) );
pairs.push_back( std::make_pair( 5, 7 ) );
TItems items;
std::transform( pairs.begin(), pairs.end(), std::back_inserter( items ),
firstElement );
Después de este código, los items
contienen 1 y 5.
otra posibilidad de C ++ 11 sería std::mem_fn
, que es similar a la solución con std::bind
:
std::transform(pairs.begin(),
pairs.end(),
std::back_inserter(items),
std::mem_fn(&std::pair<int,int>::first)
);
vea la respuesta de frerich o kotlinski para C ++ 03.
Solución de C ++ 11 con lambda:
std::transform(pairs.begin(),
pairs.end(),
std::back_inserter(items),
[](const std::pair<int, int>& p) { return p.first; });