• Publicidad

Ordenar Arreglo en Perl

Así que programas sin strict y las expresiones regulares son otro modo de hablar. Aquí encontrarás respuestas de nivel avanzado, no recomendable para los débiles de corazón.

Ordenar Arreglo en Perl

Notapor danimera » 2006-08-21 09:35 @441

Me van a Perdonar ustedes si es que Molesto mucho,y en principal Explorer Pero es que estoy haciendo un modulo que pronto publicare aqui y les agradecere mucho, Mi duda ahora es la siguiente

tengo el siguiente array

$datos[0] = "ID||apellido||edad";
$datos[1] = "01||Castro||16";
$datos[2] = "02||Gomez||21";
$datos[2] = "03||Diaz||20";

Pues la idea es que me de un segundo array ordenano por el segundo campo que es nombre de forma alfabetica

$datos_ordenados[0] = "ID||apellido||edad";
$datos_ordenados[1] = "01||Castro||16";
$datos_ordenados[2] = "03||Diaz||20";
$datos_ordenados[2] = "02||Gomez||21";

Tengo algo asi mas o menos

$campos =shift (@datos);
// Como ya se que quiero ordenar por apellidos, y que el segundo campo es el apellido entonces hago esto
($id_n,$apellido_n,$edad_n) = split(/\|\|/, $campos);
cant_reg = @datos;
$i = 1;
foreach $data (@datos){
($id,$apellido,$edad) = split(/\|\|/, $data); # esto seria como decir $datos[i];
($id_temp,$apellido_temp,$edad_temp) = split(/\|\|/, @datos[$i]); # esto seria como decir $datos[i+1] el dato que le sigue
if ($apellido <= $apellido_temp) { #aqui estaria haciendo la comparacion segun el metodo de intercambion si elemento(i) > elemento(i+1)
$temp = $data;
$j = $i-1;
$datos[$j] = $datos[$i];
$datos[$i] = $temp; #acabo de acer el intercambio, y asi continuara leyendo cada uno de los elementos y me los ordena
unshift @datos_ordenados, ($id."||".$apellido."||".$edad); # realmente esto no es que haga nada en si
}else{
push { @datos_ordenados, ($id."||".$apellido."||".$edad); # esto creo que menos
}
$i++;
}
unshift @datos, ($id_n."||".$apellido_n."||".$edad_n);
unshift @datos_ordenados, ($id_n."||".$apellido_n."||".$edad_n);
// Pero les aseguro que tengo algo malo ahi si uso en metodo de intercambio de burbuja que no tengo muy en claro como implementarlo ahi.
De todas manera el algoritmo me haria que @datos se ordenara el solo o eso pretendo, pero si me gustaria que me quedara ordenado en @datos_ordenados segun el campo que yo quiera en este caso use el apellido.
Avatar de Usuario
danimera
Perlero frecuente
Perlero frecuente
 
Mensajes: 871
Registrado: 2005-06-23 19:02 @834
Ubicación: Colombia

Publicidad

Notapor explorer » 2006-08-21 10:26 @477

Con una transformada de Schwartz es fácil hacer una ordenación de un vector por el campo y la condición que quieras:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl

@datos = qw(
  ID||apellido||edad
  01||Castro||16
  02||Gomez||21
  03||Diaz||20
);

@datos_a_ordenar = @datos[ 1 .. $#datos ];

@datos_ordenados =
  map {         $_->[0]         }
  sort{   $a->[1] cmp $b->[1]   }
  map { [ $_, (split '||')[1] ] }
  @datos_a_ordenar;

unshift @datos_ordenados, $datos[0];

print join "\n", @datos_ordenados;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
Salida:
ID||apellido||edad
01||Castro||16
03||Diaz||20
02||Gomez||21
En este caso, el campo es el 1 y se lo pasamos al split para que nos lo dé. Y la condición de comparación es '$a cmp $b' por lo que estamos ordenando alfabéticamente en orden ascendente.

Y de molestar, nada. Esta ha sido la excusa perfecta para colocar esta maravillosa construcción en este foro.
Última edición por explorer el 2006-08-27 22:32 @981, editado 3 veces en total
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor Perl user » 2006-08-21 10:27 @477

Después de un largo periodo de inactividad en foros... te dejo una pequeña respuesta, tu trabajo sería analizar como funciona, pero es sencillo.

Código: Seleccionar todo
#!/usr/bin/perl

use strict;
use warnings;

sub sort_func {
    return ( split /\|\|/, $_[0] )[1];
}

my @data = qw( ID||apellido||edad
               01||Castro||16
               03||Diaz||20
               02||Gomez||21 );
my @sorted = sort { sort_func( $a )
                      cmp
                    sort_func( $b )
                  } @data[ 1..$#data ];
print @sorted;



Saludos,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

Notapor Perl user » 2006-08-21 10:30 @479

Que tal explorer,

La Schwartzian transform generalmente se utiliza para estructuras complejas ( con referencias ) y cuya función para computar la transformación es cara, ya que bueno como podrás observar, genera un poquito de 'overhead' tras las llamadas a map/sort.

Para el problema de danimera puedes llamar directamente la función de comparación dentro del mismo bloque de sort, y así no generar tantas listas, ya que se trata de una lista plana.

Saludos,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

Notapor explorer » 2006-08-21 11:02 @501

A mí me da igual... tengo una máquina a quien le sobran megabytes y megaherzios. La seguiré usando sean las estructuras simples o complejas y el método de ordenación supere mi barrera metal de un simple sort.

Y en cuanto a la sobrecarga, estamos con el problema de siempre: intercambiar espacio por cálculos.

En la transformada se hacen 3 comparaciones y 3 llamadas a split, pero en un sort como el tuyo se hacen 3 comparaciones con 6 llamadas a la función sort_func con 6 llamadas a split.

Los números son casi los mismos, pero no escalan igual en cuanto el vector empieza a crecer. En ese caso, lo mejor para la solución de la función sort_func es 'memorizarla' con Memoize. Pero entonces estamos haciendo una ocupación de recursos de memoria, que es lo que la transformada ya hace con sus listas. Otra cosa sería hacer un benchmark, pero ahora no tengo tiempo :-)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor danimera » 2006-08-21 11:51 @535

#!/usr/bin/perl
No quiero ser empalagoso Perl User ni Explorer,

La solucion de perl User la entiendo mas o menos lo que no entiendo es la comparacion en:

my @sorted = sort { sort_func( $a ) #que es esa $a
cmp # necesito una explicacion de esta funcion
sort_func( $b ) #que es esa $b
} @data[ 1..$#data ]; #esto significa que empieza desde el indice 1??¿?

No quiero molestarles la vida, pero no podria usar ninguna esta solucionesi no la entiendo perfectamente,

con Explorer

@datos_a_ordenar = @datos[ 1 .. $#datos ]; ?? #No entiendo aqui, el escoge a partir del elemento con indice 1

@datos_ordenados =
map { $_->[0] } # Que es la funcion map que hace???¿? sera que ejecuta por cala elemento de la lista las operaciones en el bloque?¿?
sort{ $a->[1] cmp $b->[1] } # Que sucede aqui? entiendo la funcion sort pero no $a->[0]
map { [ $_, (split '||')[1] ] } # Esto lo entiendo bien
@datos_a_ordenar;

unshift @datos_ordenados, $datos[0]; #OK

print join "\n", @datos_ordenados; #OK

SI me pueden explicar estas duditas les agradeceria de lo mejor mejor,, y les mostraria el resultado de tantas de mis preguntaderas en el FORO OK.. :wink:
Avatar de Usuario
danimera
Perlero frecuente
Perlero frecuente
 
Mensajes: 871
Registrado: 2005-06-23 19:02 @834
Ubicación: Colombia

Notapor explorer » 2006-08-21 12:24 @558

danimera escribiste:@datos_a_ordenar = @datos[ 1 .. $#datos ]; ?? #No entiendo aqui, el escoge a partir del elemento con indice 1
Sí, porque no quiero ordenar el primer registro, el que vale 'ID', pues de ese sé que siempre quiero que esté en primera posición en el resultado, así que los @datos_a_ordenar serán los @datos que van desde el registro 1 hasta el último.

danimera escribiste:@datos_ordenados =
map { $_->[0] } # Que es la funcion map que hace???¿? sera que ejecuta por cala elemento de la lista las operaciones en el bloque?¿?
sort{ $a->[1] cmp $b->[1] } # Que sucede aqui? entiendo la funcion sort pero no $a->[1]
map { [ $_, (split '||')[1] ] } # Esto lo entiendo bien
@datos_a_ordenar;
La transformada de Schwartz es un proceso de 3 pasos:
  • transformación del elemento del vector original a otro elemento de vector en el que el componente a comparar está aislado de la complejidad que posee al estar dentro del elemento original, más, el propio elemento original
  • Ordenación de ese vector recien creado
  • Nueva transformación del vector ordenado en que sólo nos dedicamos a extraer los elementos originales
Como el vector fue ordenado por el campo que nos interesaba, esto es como si hubieramos indexado un vector con un índice externo. El resultado es la lectura ordenada de esos índices y sus valores acompañantes, que son los elementos originales.
  • $_->[0] : extraemos el elemento original que fue almacenado en el segundo map
  • $a->[1] : como los elementos a comparar son vectores anónimos de dos componentes, tenemos que acceder, de forma indirecta, con un '->', y con un [1] para indicar que nos referimos al segundo componente del vector.
P.D. Estamos en el foro Experto... algunas cosas no las explico porque se suponen sobreentendidas.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor Perl user » 2006-08-21 14:41 @653

explorer escribiste:A mí me da igual... tengo una máquina a quien le sobran megabytes y megaherzios. La seguiré usando sean las estructuras simples o complejas y el método de ordenación supere mi barrera metal de un simple sort.

Y en cuanto a la sobrecarga, estamos con el problema de siempre: intercambiar espacio por cálculos.

En la transformada se hacen 3 comparaciones y 3 llamadas a split, pero en un sort como el tuyo se hacen 3 comparaciones con 6 llamadas a la función sort_func con 6 llamadas a split.

Los números son casi los mismos, pero no escalan igual en cuanto el vector empieza a crecer. En ese caso, lo mejor para la solución de la función sort_func es 'memorizarla' con Memoize. Pero entonces estamos haciendo una ocupación de recursos de memoria, que es lo que la transformada ya hace con sus listas. Otra cosa sería hacer un benchmark, pero ahora no tengo tiempo :-)


Totalmente de acuerdo, las máquinas hoy en día son tan poderosas que reducciones así no importan mucho, pero aunque sea poderosa, siempre hay cambios de un algoritmo a otro, siempre es SIEMPRE, posiblemente en estructuras pequeñas ( dudo mucho que el ejemplo de danimera sea muy enorme ) pues es demasiado trivial.

Pero el diseño de algoritmos "eficientes" si es importante, ahora bien... las operaciones realizadas por la schwartzian transform aparte de las que mencionaste es el uso de map :), map genera listas nuevas recuerda.

El punto clave de esta serie de comentarios es pues, destacar cuando una transformada de schwartz es necesaria, en palabras del mismo Randal, que fué lo que cité arriba.

Pero totalmente de acuerdo, eres libre de usar lo que mas te acomode.

Saludos,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

Notapor explorer » 2006-08-21 18:22 @807

Lo que pasa es que... como me aprendí la transformada de Schawrtz leyendo el libro 'Perl Cookbook', con un ejemplo sencillo, pues que al final lo aplicas hasta donde no debes.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Avanzado

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 4 invitados