Aporte C++: Utilidades de la STL que tal vez no conoces

Iniciado por eferion, 2 Julio 2014, 13:29 PM

0 Miembros y 1 Visitante están viendo este tema.

eferion

Muchas veces, al hacer programas nos dedicamos a reinventar la rueda. Unas veces es para aprender, pero otras muchas es por simple desconocimiento de las herramientas de las que disponemos.

He aquí algunos ejemplos, aunque hay que tener en cuenta lo siguiente:


  • Algunos ejemplos solo funcionarán con compiladores compatibles con C++11.
  • Para entender los ejemplos es necesario tener una base mínima ( familiarizarse con contenedores e iteradores, por ejemplo )
  • Los ejemplos no intentan hacer uso del algoritmo más óptimo o más rápido o más ... son simplemente ilustrativos. La opción más óptima dependerá de los requisitos propios de cada aplicación.

Si el aporte os resulta interesante intentaré ampliarlo conforme tenga tiempo libre.

Ordenar un vector:

std::sort es el primero de los grandes desconocidos. Esta función, bien utilizada, nos permite ordenar con facilidad casi cualquier tipo de vector, lista, arreglo, ... para ello nos apoyamos en las funciones std::begin y std::end, nuevas en C++11, que permiten obtener iteradores incluso para arreglos.

Si usamos C++11, podemos también diseñar nuestras propias funciones de ordenación basándonos en funciones lambda, como se verá más adelante.

Apoyándonos en las funciones std::begin y std::end podemos
Código (cpp) [Seleccionar]

#include <algorithm>
#include <functional>
#include <iostream>

int main( )
{
 int numeros[] = {3, 5, 7, 2, 9, 1, 4, 8, 6 };

 std::cout << "Orden de mayor a menor" << std::endl;
 std::sort ( std::begin(numeros), std::end(numeros), std::greater< int >( ) );
 for ( auto it = std::begin( numeros ); it != std::end( numeros ); ++it )
   std::cout << *it << ' ';
 std::cout << std::endl;

 std::cout << "Orden de menor a mayor" << std::endl;
 std::sort ( std::begin(numeros), std::end(numeros), std::less< int >( ) );
 for ( auto it = std::begin( numeros ); it != std::end( numeros ); ++it )
   std::cout << *it << ' ';
 std::cout << std::endl;
 return 0;
}


Conteo de elementos en un vector

En el foro suele ser habitual que alguien pida ayuda saber cuántos elementos de un arreglo cumplen una serie de características...

Normalmente las soluciones pasan por poner un for con uno o varios ifs en su interior... con lo limpio que puede llegar a quedar usando las instrucciones adecuadas.

greater_equal es un template que implementa el operador función. Dicho operador requiere 2 parámetros... el primero es el valor a comprobar y el segundo el valor de referencia. El operador devuelve true si el primer parámetro es mayor o igual al segundo. Debido a que el parámetro que sirve de referencia es el segundo, se hace necesario usar la funcion bind2nd "bind second", que permite asignar un valor fijo al segundo parámetro a lo largo de todas las llamadas.

finalmente count_if se encarga de recorrer los iteradores y realiza un conteno de todas las comprobaciones que arrojan un resultado positivo.

El resultado es una comparación programada en un par de líneas.

Para comparaciones más complejas se puede usar una expresión lambda, una función propia o una clase que implemente el operador función, como puede verse en los ejemplos.

Código (cpp) [Seleccionar]

#include <algorithm>
#include <functional>
#include <iostream>

bool pares( int num )
{
 return num % 2 == 0;
}

class DivisiblePorN
{
 public:

   DivisiblePorN( int divisor )
     : _divisor( divisor )
   { }

   bool operator( )( int numero )
   {
     return ( numero % _divisor == 0 );
   }

 private:

   int _divisor;
};

int main( )
{
 int numeros[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
 int resultado = std::count_if( std::begin( numeros ), std::end( numeros ),
                                std::bind2nd( std::greater_equal< int >( ), 7 ) );
 std::cout << "Numeros mayores o iguales a 7: " << resultado << std::endl;

 resultado = std::count_if( std::begin( numeros ), std::end( numeros ),
                            []( int num ){ return num%2; } );
 std::cout << "Numeros impares: " << resultado << std::endl;

 resultado = std::count_if( std::begin( numeros ), std::end( numeros ), pares );
 std::cout << "Numeros pares: " << resultado << std::endl;

 DivisiblePorN divisible3( 3 );
 resultado = std::count_if( std::begin( numeros ), std::end( numeros ), divisible3 );
 std::cout << "Numeros divisibles entre 3: " << resultado << std::endl;

 return 0;
}


Intercambiar el valor de dos variables

El titular lo dice todo... podemos hacer uso la opción larga que todo el mundo conoce ( en cualquiera de sus variantes ) o dejar que la stl haga el "trabajo sucio:

Código (cpp) [Seleccionar]

#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>

int main( )
{
 int x = 1;
 int y = 2;

 std::swap( x, y );

 std::cout << "X = " << x << "; Y = " << y << std::endl << std::endl;

 int v1[] = { 1, 2, 3, 4 };
 int v2[] = { 5, 6, 7, 8 };
 std::swap( v1, v2 );

 std::cout << "v1 = {";
 for ( auto i : v1 )
   std::cout << " " << i;
 std::cout << " }" << std::endl;
 std::cout << "v2 = {";
 for ( auto i : v2 )
   std::cout << " " << i;
 std::cout << " }" << std::endl << std::endl;

 std::vector< int > vector1 = { 10, 20, 30, 40 };
 std::vector< int > vector2 = { 50, 60, 70, 80 };
 std::swap( vector1, vector2 );

 std::cout << "vector1 = {";
 for_each( vector1.begin( ), vector1.end( ), []( int num ){ std::cout << " " << num; } );
 std::cout << " }" << std::endl;

 std::cout << "vector2 = {";
 for_each( vector2.begin( ), vector2.end( ), []( int num ){ std::cout << " " << num; } );
 std::cout << " }" << std::endl;

 return 0;
}


Sumar valores

"Tengo que devolver la suma de todos los valores del arreglo"... ¿te suena esta frase? La primera solución que aparece en la mente de más de uno pasa por inicializar un contador, poner un bucle for e ir acumulando valores... no hace falta:

Código (cpp) [Seleccionar]

#include <functional>
#include <iostream>
#include <numeric>

int main( )
{
 int numeros[] = { 20, 45, 86, 91, 10, 25, 4, 17, 62 };

 std::cout << "Suma total: ";
 std::cout << std::accumulate(std::begin( numeros ), std::end( numeros ), 0 );
 std::cout << std::endl;
}


¿Y si sólo queremos saber la suma de aquellos que cumplan una condición determinada? Sin problemas, únicamente tenemos que aplicar lo que hemos visto en apartados anteriores:

Código (cpp) [Seleccionar]

#include <functional>
#include <iostream>
#include <numeric>

class AddLessThanN
{
 public:

   AddLessThanN( int n )
     : _limit( n )
   {

   }

   int operator( )( int accum, int x )
   {
     if ( x < _limit )
       accum += x;

     return accum;
   }

 private:

   int _limit;
};

int main( )
{
 int numeros[] = { 20, 45, 86, 91, 10, 25, 4, 17, 62 };

 AddLessThanN lessThan( 20 );
 std::cout << "Sumar elementos menores que 20: ";
 std::cout << std::accumulate(std::begin( numeros ), std::end( numeros ), 0, lessThan );
 std::cout << std::endl;
}


Eliminar elementos de un vector

La opciónes tradicionales pasan todas por usar un bucle for y luego, o hacer malabares con los iteradores, añadir los elementos a eliminar en una lista... o crear una lista nuevo con los elementos válidos...

Código (cpp) [Seleccionar]

#include <algorithm>
#include <iostream>
#include <vector>

int main( )
{
 std::vector< int > numeros = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

 std::vector< int >::iterator it = std::remove_if ( numeros.begin( ), numeros.end( ), [](int num){ return num%2; } );
 numeros.erase( it, numeros.end( ) );

 std::cout << "Solo pares: ";
 for_each( numeros.begin( ), numeros.end( ), []( int num){ std::cout << num << " "; } );
 std::cout << std::endl;

 return 0;
}


PD.: también funciona con arreglos:

Código (cpp) [Seleccionar]

#include <algorithm>
#include <iostream>
#include <vector>

int main( )
{
 int numeros[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

 int* itEnd = std::remove_if ( std::begin( numeros ), std::end( numeros ), [](int num){ return num%2 == 0; } );

 std::cout << "Solo impares: ";
 for_each( std::begin( numeros ), itEnd, []( int num){ std::cout << num << " "; } );
 std::cout << std::endl;

 return 0;
}



vangodp

 ;-) Gracias man. Que artista eres =D
Voy a estudiarlo.
Suerte!

nolasco281

Genial muchas gracias por los ejemplos solo tengo una pregunta:

En que parte de los ejemplos se utilizan estas librerias y para que? muchas gracias por compartir y suga aumentadolo si queda tiempo

Código (cpp) [Seleccionar]

#include <algorithm>
#include <utility>


PD:Ya investique que son pero tal vez me puede dar  un concepto mas general de como las uso.

Saludos y gracias.
Lo que se puede imaginar... se puede programar.

leosansan

Cita de: nolasco281 en  4 Julio 2014, 00:18 AM
.........................................................
En que parte de los ejemplos se utilizan estas librerias y para que? muchas gracias por compartir y suga aumentadolo si queda tiempo

Código (cpp) [Seleccionar]

#include <algorithm>
#include <utility>

....................................................







eferion

Cita de: nolasco281 en  4 Julio 2014, 00:18 AM
Genial muchas gracias por los ejemplos solo tengo una pregunta:

En que parte de los ejemplos se utilizan estas librerias y para que? muchas gracias por compartir y suga aumentadolo si queda tiempo

Código (cpp) [Seleccionar]

#include <algorithm>
#include <utility>


PD:Ya investique que son pero tal vez me puede dar  un concepto mas general de como las uso.

Saludos y gracias.

algorithm tiene una colección de clases y funciones para trabajar con rangos de datos ( vectores, matrices, arreglos, ... ).

utility permite, por ejemplo trabajar con el template "pair". En un principio se podría decir que "utility" sirve de saco para aquellas utilidades que no han sabido ubicar en una librería más apropiada.