[caracas-pm] Ejemplos de la Reunión Anterior

Ernesto Hernández-Novich emhn at telcel.net.ve
Sat Jan 22 08:14:01 PST 2005


* map/split y join/map
  "Ernesto" -> Lista de valores ASCII -> "otsenrE"

$, = ", ";
my $string = "Ernesto";
my @ascii = map { ord($_) } split //,$string;
print @ascii,"\n";
$, = "";
$string = join "",map { chr($_) } reverse(@ascii);
print $string,"\n";

* El ejercicio propuesto por la audiencia. Se tiene un hash y se quiere
reconstruir de manera que todas las _claves_ sean convertidas a
mayúscula. (Tip: usar Data::Dumper para ver %o _antes_ y %n _después_;
nos valemos del truco de que un hash no es más que una lista cuyas
posiciones pares son claves e impares son valores).

my %o = ( 'a' => 'b',
          'c' => 'd',
          'e' => 1,
          'f' => 'H' );
my %n = map { uc($_) => $o{$_}  } (keys %o);

* "Programación procedural es más rápida que la funcional". Dada una
lista de 100.000 números escogidos al azar en [0..1000], generar una
lista con los números únicos (es decir, eliminar duplicados). Se
escriben dos funciones, una implementa de la mejor manera posible el
algoritmo obvio procedural, la otra implementa la manera simple
funcional; se usa Benchmark para demostrar cuál es más rápida. Nota:
agregué 'classic-plus' que fue la sugerencia de José Luis de usar
asignación a 1 en lugar de incrementar.

use Benchmark;
sub classic {
  my @list  = @_;
  my %visto = ();
  foreach (@list) {
    $visto{$_}++;
  }
  return keys %visto;
}
sub classic_plus {
  my @list  = @_;
  my %visto = ();
  foreach (@list) {
    $visto{$_} = 1;
  }
  return keys %visto;
}
sub functional {
  my @list = @_;
  my %visto = ();
  return grep { ! $visto{$_}++ } @list;
}
my @list = map { int(rand(1000)) } (1..100000);
timethese (1000000, {
  'classic'    => 'classic(@list)',
  'classic+'   => 'classic_plus(@list)',
  'functional' => 'functional(@list)'
});

* map "útil" vs. map "inútil". El map usando print es inútil porque no
se utiliza para nada la lista generada (es un desperdicio de espacio y
tiempo). No obstante el map/grep interon es utilísimo y hace que el
algoritmo se vea más compacto y además sea más rápido que el algoritmo
procedural equivalente.

# Sea @p una lista de coeficientes de ecuaciones cuadráticas,
# obtener una lista con las raíces, siempre y cuando sean reales.
#
#          2
# Si y = ax  + bx + c
#
# d = b * b - 4 * a * c,   d < 0 => Raiz imaginaria
#                          d > 0 => Raíces ( -b +/- sqrt(d) ) / 2 * a
my @p = ( [1,2,1], [1,1,1], [4,3,5], [1,0,-4], [1,16,4] );
sub d {
  my ($a,$b,$c) = @_;
  return $b * $b - 4 * $a * $c;
}
sub raices {
  my ($a,$b,$c) = @_;
  my $d = d($a,$b,$c);
  return [ ( -$b + sqrt($d) )  / (2 * $a), 
           ( -$b - sqrt($d) ) / (2 * a) ];
}
map { print "(", join(",",@{$_}), ")\n"; }
    map { raices( @{$_} ) }
        grep { d( @{$_} ) >= 0 } @p;

* La maniobra de Schwartz. Se quiere ordenar una lista de archivos según
su tamaño; el algoritmo procedural obvio tiene una línea, mientras que
el algoritmo funcional aplicando la maniobra de Schwartz es menos obvio
pero es humillantemente más rápido.

use Benchmark;
timethese(200, {
  'classic'  => '@sorted = sort { -s $a <=> -s $b } glob "/usr/bin/*"',
  'schwartz' => '@sorted = map  { $_->[0] }
                           sort { $a->[1] <=> $b->[1] }
                           map  { [$_,-s $_] } glob "/usr/bin/*"'
} );

-- 
Ernesto Hernández-Novich - On Linux 2.6.10 i686 - Unix: Live free or die!
Geek by nature, Linux by choice, Debian of course.
If you can't apt-get it, it isn't useful or doesn't exist.
GPG Key Fingerprint = 438C 49A2 A8C7 E7D7 1500 C507 96D6 A3D6 2F4C 85E3



More information about the caracas-pm mailing list