• Publicidad

Eliminar elementos de un array

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Eliminar elementos de un array

Notapor Zeokat » 2007-12-21 22:08 @964

Bien, yo tengo un array con palabras

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
@palabras=("raton","perro","vaca","caballo","gato","aguila","salmon");
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Con una expresión regular compruebo que la palabra NO tenga la letra a y si esto resulta verdadero elimina ese elemento del array. En este caso eliminaría la palabra "perro".

Estuve ojeando algunos tutoriales y solo encontré cómo quitar el último elemento del arreglo con pop, o quitar el primer elemento con shift y encontré algo de delete aquí: viewtopic.php?t=951.html pero parece que es para hashes... mmm... ¿alguna idea?

Gracias de antemano.
Zeokat
Perlero nuevo
Perlero nuevo
 
Mensajes: 125
Registrado: 2006-08-22 08:08 @380

Publicidad

Notapor explorer » 2007-12-21 23:56 @039

Lo que tu dices que necesitas es splice().

Pero, ¡ojo!. ¡El tamaño del array cambia!

Eso quiere decir que si estás haciendo un bucle usando los índices para referenciar a los elementos, al eliminar un elemento intermedio hay que tener en cuenta que el índice ya no apunta al actual elemento, sino a uno nuevo.

Ejemplo. El siguiente programa
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl

@palabras = qw( raton perro vaca caballo gato aguila salmon );

print "Inicio: @palabras\n";

for ($i = 0; $i < @palabras; $i++ ) {
    print "analizando $palabras[$i]\n";
    if ( $palabras[$i] !~ /a/ ) {
        splice(@palabras, $i, 1);
        print "    eliminando...\n";
    }
}

print "Final: @palabras\n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
genera
Código: Seleccionar todo
Inicio: raton perro vaca caballo gato aguila salmon
analizando raton
analizando perro
    eliminando...
analizando caballo
analizando gato
analizando aguila
analizando salmon
Final: raton vaca caballo gato aguila salmon
Fíjate: al eliminar el perro, ¡nos saltamos a la vaca!. Es debido a que vamos incrementando $i de uno en uno, pero al eliminar un elemento intermedio, todos los elementos que le siguen, hasta el final, van ocupando su posición: la 'vaca' ahora ocupa la posición del 'perro'... al seguir el bucle e incrementar $i, ahora en vez de analizar a la 'vaca', nos encontramos con un caballo.

La solución es... un arcano de Perl llamado redo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl

@palabras = qw( raton perro vaca caballo gato aguila salmon );

print "Inicio: @palabras\n";

for ($i = 0; $i < @palabras; $i++ ) {
    print "analizando $palabras[$i]\n";
    if ( $palabras[$i] !~ /a/ ) {
        splice(@palabras, $i, 1);
        print "    eliminando...\n";
        redo;
    }
}

print "Final: @palabras\n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Fíjate que es el mismo programa, pero añadimos un redo dentro del if. Su función es 'empezar de nuevo el bucle sin pasar por la condición ni por el incremento'. Vamos, que repetimos el bucle interno.

Al repetirlo, $i no ha sido incrementado, PERO como los elementos dentro del array se han movido, SÍ que está apuntando al siguiente elemento a analizar ('vaca'):
Código: Seleccionar todo
Inicio: raton perro vaca caballo gato aguila salmon
analizando raton
analizando perro
    eliminando...
analizando vaca
analizando caballo
analizando gato
analizando aguila
analizando salmon
Final: raton vaca caballo gato aguila salmon


De todas formas, hay otras formas de hacer lo que quieres: exactamente como lo que has dicho:
Con una expresión regular compruebo que la palabra NO tenga la letra a y si esto resulta verdadero elimina ese elemento del array
pero reescrito de otra forma...
Con una expresión regular me quedo con las palabras que SI tengan la letra a

Luego queda así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
@palabras = grep { /a/ } @palabras;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
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 Zeokat » 2007-12-22 09:45 @448

Vaya excelente respuesta explorer, me dio una idea de lo que tengo que hacer.

Estuve probando pero no conseguí mi objetivo, es que me expliqué mal. Al final debo tener dos arrays uno con las palabras que tienen la letra "a" y otro array con las palabras que no tienen la letra "a".

Sería hacer una resta de arrays.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
@palabras=("raton","perro","vaca","caballo","gato","aguila","salmon");
@palabras_a = grep { /a/ } @palabras;
@palabras_b  #"seria la resta del array @palabras menos el array @palabras_a, no se si podría hacer esta resta o quizás esta tarea se haga de otra forma más rápida..."
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Zeokat
Perlero nuevo
Perlero nuevo
 
Mensajes: 125
Registrado: 2006-08-22 08:08 @380

Notapor explorer » 2007-12-22 12:29 @561

Se puede hacer de muchas formas, incluso con un simple if que fuese actualizando dos arrays según el valor de la comparación.

Yo aquí de la manera más complicada: con un módulo:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use List::MoreUtils qw/part/;

@palabras  = qw(raton perro vaca caballo gato aguila salmon);

@repartido = part { /a/ } @palabras;

print "Sin 'a': ", join(q{,}, @{ $repartido[0] }), "\n";
print "Con 'a': ", join(q{,}, @{ $repartido[1] }), "\n";
 
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Es complicado... pero se resuelve en una línea :-)
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 Zeokat » 2007-12-22 13:47 @616

Pues sí, sí que es una solución complicada, jejeje. Yo no quería echar mano de módulos adicionales. Parece que mi ActivePerl no trae ese módulo... Bueno, a ver qué se me ocurre.

Vaya, lo del if me ha dado una idea... haré eso que vaya agregando elementos a dos arrays diferentes.

Buena idea. :)

Gracias de nuevo, explorer. Feliz navidad.
Zeokat
Perlero nuevo
Perlero nuevo
 
Mensajes: 125
Registrado: 2006-08-22 08:08 @380

Notapor explorer » 2007-12-22 18:25 @809

Esta es la forma perversa:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
foreach $p ( @palabras ) {
    /a/ ? push @con, $p : push @sin, $p;
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Y esta es algo rara:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
push @{$otras[/a/]}, $_ for @palabras;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
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

No hay nada perverso en esa

Notapor Jenda » 2007-12-23 07:02 @335

explorer escribiste:Esta es la forma perversa:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
foreach $p ( @palabras ) {
    /a/ ? push @con, $p : push @sin, $p;
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4



No hay nada perverso, pero en este caso no hay razón para usar el operador ?:. Me parece mejor usar un if.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
foreach my $p ( @palabras ) {
    if (/a/) {
        push @con, $p
    } else {
        push @sin, $p;
    }
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Y es mejor siempre usar el "my" antes del nombre de la variable porque queremos que exista solo dentro del foreach{}.
Jenda
Perlero nuevo
Perlero nuevo
 
Mensajes: 132
Registrado: 2007-10-29 06:31 @313
Ubicación: Praga, Republica Checa

Notapor explorer » 2007-12-23 11:09 @506

Decía que era perverso porque estoy utilizando un operador de forma 'indebida', ya que ?: devuelve un valor, que no estoy usando. Solo lo utilizo porque es más corto escribirlo así que con el if. Pero tienes razón, lo ideal es el if.

En cuanto a lo del my: solo es necesario en un ambiente 'strict' (que en estos ejemplos no hemos usado). Además, la variable usada por foreach se convierte en local dentro del bucle, por lo que no afecta a otra posible variable $p del exterior.

Lo he hecho de forma excepcional, porque en el foro Básico voy intercalando los ejemplos con 'strict' y sin él.

Lo ideal es usar my, desde luego.
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 Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado