es necesario eliminar todas las listas de directorios de formularios de elementos que no son de archivo y "array = grep {-f $ _} array" funcionó como un encanto para mí :)
taiko
Respuestas:
87
Utilice empalme si ya conoce el índice del elemento que desea eliminar.
Grep funciona si estás buscando.
Si necesita hacer muchos de estos, obtendrá un rendimiento mucho mejor si mantiene su matriz en orden ordenado, ya que luego puede hacer una búsqueda binaria para encontrar el índice necesario.
Si tiene sentido en su contexto, es posible que desee considerar el uso de un "valor mágico" para los registros eliminados, en lugar de eliminarlos, para ahorrar en el movimiento de datos; por ejemplo, establezca los elementos eliminados en undef. Naturalmente, esto tiene sus propios problemas (si necesita saber el número de elementos "en vivo", debe realizar un seguimiento de ellos por separado, etc.), pero puede valer la pena según su aplicación.
Editar En realidad, ahora que echo un segundo vistazo, no use el código grep anterior. Sería más eficiente encontrar el índice del elemento que desea eliminar, luego use splice para eliminarlo (el código que tiene acumula todos los resultados que no coinciden ..)
my $index = 0;
$index++ until $arr[$index] eq 'foo';
splice(@arr, $index, 1);
Eso eliminará la primera aparición. Eliminar todas las apariciones es muy similar, excepto que querrá obtener todos los índices en una sola pasada:
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
El resto se deja como ejercicio para el lector; recuerde que la matriz cambia a medida que la empalma.
Edit2 John Siracusa señaló correctamente que tenía un error en mi ejemplo ... arreglado, lo siento.
si no se encuentra la cadena, el bucle se atascará, así que mi $ index = 0; my $ count = scalar @arr; $ index ++ hasta $ arr [$ index] eq 'foo' o $ index == $ count; empalme (@arr, $ índice, 1);
Amir.F
1
o my ($index) = grep { $arr[$_] eq 'foo' } 0..$#arr; if (defined $index) {splice(@arr, $index, 1); }- para el primer partido
Reflexivo
13
splice eliminará los elementos de la matriz por índice. Utilice grep, como en su ejemplo, para buscar y eliminar.
Gracias, spoulson. No tengo los índices que tengo que borrar y tuve que recurrir a grep.
user21246
8
¿Es esto algo que vas a hacer mucho? Si es así, es posible que desee considerar una estructura de datos diferente. Grep buscará en toda la matriz cada vez y una matriz grande podría ser bastante costosa. Si la velocidad es un problema, es posible que desee considerar usar un Hash en su lugar.
En su ejemplo, la clave sería el número y el valor sería el recuento de elementos de ese número.
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
a
my @del_indexes = reverse(grep { $arr[$_] eq 'foo' } 0..$#arr);
Esto evita el problema de la renumeración de la matriz eliminando primero los elementos de la parte posterior de la matriz. Poner un empalme () en un bucle foreach limpia @arr. Relativamente simple y legible ...
Particularmente me gusta la lógica y la elegancia de este enfoque.
Keve
Sí, de hecho, incluso puedes escribirlo en una sola línea como: @arr = @arr[grep ...]que me gusta particularmente. No estoy seguro de cuán eficiente es, pero voy a empezar a usarlo porque no puede ser peor que las otras soluciones.
soger
3
Creo que su solución es la más simple y fácil de mantener.
El resto de la publicación documenta la dificultad de convertir las pruebas de elementos en splicecompensaciones. Por lo tanto, haciéndolo más completo respuesta .
Mire los giros por los que tiene que pasar para tener un algoritmo eficiente (es decir, de una pasada) para convertir las pruebas en los elementos de la lista en índices. Y no es tan intuitivo en absoluto.
subarray_remove ( \@& ) {
my ( $arr_ref, $test_block ) = @_;
my $sp_start = 0;
my $sp_len = 0;
for ( my $inx = 0; $inx <= $#$arr_ref; $inx++ ) {
local $_ = $arr_ref->[$inx];
nextunless $test_block->( $_ );
if ( $sp_len > 0 && $inx > $sp_start + $sp_len ) {
splice( @$arr_ref, $sp_start, $sp_len );
$inx = $inx - $sp_len;
$sp_len = 0;
}
$sp_start = $inx if ++$sp_len == 1;
}
splice( @$arr_ref, $sp_start, $sp_len ) if $sp_len > 0;
return;
}
Es probable que la eliminación en el valor de la matriz quede obsoleta (consulte su documento)
e2-e4
3
esto simplemente elimina el valor almacenado en ese índice de matriz. al menos en mi versión de perl, (5.14)
Rooster
Esto realmente NO borra lo que piensas. Solo borra el valor, haciéndolo undef. Además, del documento vinculado por ringø: "ADVERTENCIA: Se desaconseja encarecidamente llamar a delete en valores de matriz. La noción de eliminar o verificar la existencia de elementos de matriz de Perl no es conceptualmente coherente y puede conducir a un comportamiento sorprendente". (el párrafo anterior en el documento tiene todos los detalles sangrientos).
mivk
2
Elimina todas las apariciones de 'algo' si matriz.
Basado en las respuestas de SquareCog:
my @arr = ('1','2','3','4','3','2', '3','4','3');
my @dix = grep { $arr[$_] eq '4' } 0..$#arr;
my $o = 0;
for (@dix) {
splice(@arr, $_-$o, 1);
$o++;
}
printjoin("\n", @arr);
Cada vez que eliminemos un índice de @arr, el siguiente índice correcto para eliminar será $_-current_loop_step.
undef establece el valor del elemento en nulo. Los elementos totales (tamaño) siguen siendo los mismos.
Boontawee Home
1
@BoontaweeHome, grepal final, los elimina.
Deanna
1
Solo para estar seguro de haber comparado las soluciones grep y map, primero buscando índices de elementos coincidentes (los que se deben eliminar) y luego eliminando directamente los elementos mediante grep sin buscar los índices. Parece que la primera solución propuesta por Sam al hacer su pregunta ya era la más rápida.
use Benchmark;
my @A=qw(A B C A D E A F G H A I J K L A M N);
my @M1; my @G; my @M2;
my @Ashrunk;
timethese( 1000000, {
'map1' => sub{
my $i=0;
@M1 = map { $i++; $_ eq 'A' ? $i-1 : ();} @A;
},
'map2' => sub{
my $i=0;
@M2 = map { $A[$_] eq 'A' ? $_ : () ;} 0..$#A;
},
'grep' => sub{
@G = grep { $A[$_] eq 'A' } 0..$#A;
},
'grem' => sub{
@Ashrunk = grep { $_ ne'A' } @A;
},
});
El resultado es:
Benchmark: timing 1000000 iterations of grem, grep, map1, map2...
grem: 4 wallclock secs ( 3.37 usr + 0.00 sys = 3.37 CPU) @ 296823.98/s (n=1000000)
grep: 3 wallclock secs ( 2.95 usr + 0.00 sys = 2.95 CPU) @ 339213.03/s (n=1000000)
map1: 4 wallclock secs ( 4.01 usr + 0.00 sys = 4.01 CPU) @ 249438.76/s (n=1000000)
map2: 2 wallclock secs ( 3.67 usr + 0.00 sys = 3.67 CPU) @ 272702.48/s (n=1000000)
M1 = 0361015
M2 = 0361015
G = 0361015
Ashrunk = B C D E F G H I J K L M N
Como lo muestran los tiempos transcurridos, es inútil intentar implementar una función de eliminación utilizando índices definidos por grep o por mapas. Simplemente grep-remove directamente.
Antes de probar, pensaba que "map1" sería el más eficiente ... Supongo que debería confiar más en Benchmark. ;-)
Si conoce el índice de la matriz, puede eliminarlo () . La diferencia entre splice () y delete () es que delete () no vuelve a numerar los elementos restantes de la matriz.
De hecho, quise decir renumerar, que según Perldoc, splice () hace.
Powerlord
0
Un código similar que escribí una vez para eliminar cadenas que no comienzan con SB.1 de una matriz de cadenas
my @adoSymbols=('SB.1000','RT.10000','PC.10000');
##Remove items from an array from backwardfor(my $i=$#adoSymbols;$i>=0;$i--) {
unless ($adoSymbols[$i] =~ m/^SB\.1/) {splice(@adoSymbols,$i,1);}
}
Respuestas:
Utilice empalme si ya conoce el índice del elemento que desea eliminar.
Grep funciona si estás buscando.
Si necesita hacer muchos de estos, obtendrá un rendimiento mucho mejor si mantiene su matriz en orden ordenado, ya que luego puede hacer una búsqueda binaria para encontrar el índice necesario.
Si tiene sentido en su contexto, es posible que desee considerar el uso de un "valor mágico" para los registros eliminados, en lugar de eliminarlos, para ahorrar en el movimiento de datos; por ejemplo, establezca los elementos eliminados en undef. Naturalmente, esto tiene sus propios problemas (si necesita saber el número de elementos "en vivo", debe realizar un seguimiento de ellos por separado, etc.), pero puede valer la pena según su aplicación.
Editar En realidad, ahora que echo un segundo vistazo, no use el código grep anterior. Sería más eficiente encontrar el índice del elemento que desea eliminar, luego use splice para eliminarlo (el código que tiene acumula todos los resultados que no coinciden ..)
my $index = 0; $index++ until $arr[$index] eq 'foo'; splice(@arr, $index, 1);
Eso eliminará la primera aparición. Eliminar todas las apariciones es muy similar, excepto que querrá obtener todos los índices en una sola pasada:
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
El resto se deja como ejercicio para el lector; recuerde que la matriz cambia a medida que la empalma.
Edit2 John Siracusa señaló correctamente que tenía un error en mi ejemplo ... arreglado, lo siento.
fuente
my ($index) = grep { $arr[$_] eq 'foo' } 0..$#arr; if (defined $index) {splice(@arr, $index, 1); }
- para el primer partidosplice eliminará los elementos de la matriz por índice. Utilice grep, como en su ejemplo, para buscar y eliminar.
fuente
¿Es esto algo que vas a hacer mucho? Si es así, es posible que desee considerar una estructura de datos diferente. Grep buscará en toda la matriz cada vez y una matriz grande podría ser bastante costosa. Si la velocidad es un problema, es posible que desee considerar usar un Hash en su lugar.
En su ejemplo, la clave sería el número y el valor sería el recuento de elementos de ese número.
fuente
si cambias
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
a
my @del_indexes = reverse(grep { $arr[$_] eq 'foo' } 0..$#arr);
Esto evita el problema de la renumeración de la matriz eliminando primero los elementos de la parte posterior de la matriz. Poner un empalme () en un bucle foreach limpia @arr. Relativamente simple y legible ...
foreach $item (@del_indexes) { splice (@arr,$item,1); }
fuente
Puede usar el corte de matriz en lugar de empalmar. Grep para devolver los índices que desea conservar y usar el corte:
my @arr = ...; my @indicesToKeep = grep { $arr[$_] ne 'foo' } 0..$#arr; @arr = @arr[@indiciesToKeep];
fuente
@arr = @arr[grep ...]
que me gusta particularmente. No estoy seguro de cuán eficiente es, pero voy a empezar a usarlo porque no puede ser peor que las otras soluciones.Creo que su solución es la más simple y fácil de mantener.
El resto de la publicación documenta la dificultad de convertir las pruebas de elementos en
splice
compensaciones. Por lo tanto, haciéndolo más completo respuesta .Mire los giros por los que tiene que pasar para tener un algoritmo eficiente (es decir, de una pasada) para convertir las pruebas en los elementos de la lista en índices. Y no es tan intuitivo en absoluto.
sub array_remove ( \@& ) { my ( $arr_ref, $test_block ) = @_; my $sp_start = 0; my $sp_len = 0; for ( my $inx = 0; $inx <= $#$arr_ref; $inx++ ) { local $_ = $arr_ref->[$inx]; next unless $test_block->( $_ ); if ( $sp_len > 0 && $inx > $sp_start + $sp_len ) { splice( @$arr_ref, $sp_start, $sp_len ); $inx = $inx - $sp_len; $sp_len = 0; } $sp_start = $inx if ++$sp_len == 1; } splice( @$arr_ref, $sp_start, $sp_len ) if $sp_len > 0; return; }
fuente
Yo suelo:
delete $array[$index];
Eliminar Perldoc .
fuente
undef
. Además, del documento vinculado por ringø: "ADVERTENCIA: Se desaconseja encarecidamente llamar a delete en valores de matriz. La noción de eliminar o verificar la existencia de elementos de matriz de Perl no es conceptualmente coherente y puede conducir a un comportamiento sorprendente". (el párrafo anterior en el documento tiene todos los detalles sangrientos).Elimina todas las apariciones de 'algo' si matriz.
Basado en las respuestas de SquareCog:
my @arr = ('1','2','3','4','3','2', '3','4','3'); my @dix = grep { $arr[$_] eq '4' } 0..$#arr; my $o = 0; for (@dix) { splice(@arr, $_-$o, 1); $o++; } print join("\n", @arr);
Cada vez que eliminemos un índice de
@arr
, el siguiente índice correcto para eliminar será$_-current_loop_step
.fuente
Puede utilizar el grupo de no captura y una lista de elementos delimitados por tubería para eliminar.
perl -le '@ar=(1 .. 20);@x=(8,10,3,17);$x=join("|",@x);@ar=grep{!/^(?:$x)$/o} @ar;print "@ar"'
fuente
Lo mejor que encontré fue una combinación de "undef" y "grep":
foreach $index ( @list_of_indexes_to_be_skiped ) { undef($array[$index]); } @array = grep { defined($_) } @array;
¡Eso hace el truco! Federico
fuente
grep
al final, los elimina.Solo para estar seguro de haber comparado las soluciones grep y map, primero buscando índices de elementos coincidentes (los que se deben eliminar) y luego eliminando directamente los elementos mediante grep sin buscar los índices. Parece que la primera solución propuesta por Sam al hacer su pregunta ya era la más rápida.
use Benchmark; my @A=qw(A B C A D E A F G H A I J K L A M N); my @M1; my @G; my @M2; my @Ashrunk; timethese( 1000000, { 'map1' => sub { my $i=0; @M1 = map { $i++; $_ eq 'A' ? $i-1 : ();} @A; }, 'map2' => sub { my $i=0; @M2 = map { $A[$_] eq 'A' ? $_ : () ;} 0..$#A; }, 'grep' => sub { @G = grep { $A[$_] eq 'A' } 0..$#A; }, 'grem' => sub { @Ashrunk = grep { $_ ne 'A' } @A; }, });
El resultado es:
Benchmark: timing 1000000 iterations of grem, grep, map1, map2... grem: 4 wallclock secs ( 3.37 usr + 0.00 sys = 3.37 CPU) @ 296823.98/s (n=1000000) grep: 3 wallclock secs ( 2.95 usr + 0.00 sys = 2.95 CPU) @ 339213.03/s (n=1000000) map1: 4 wallclock secs ( 4.01 usr + 0.00 sys = 4.01 CPU) @ 249438.76/s (n=1000000) map2: 2 wallclock secs ( 3.67 usr + 0.00 sys = 3.67 CPU) @ 272702.48/s (n=1000000) M1 = 0 3 6 10 15 M2 = 0 3 6 10 15 G = 0 3 6 10 15 Ashrunk = B C D E F G H I J K L M N
Como lo muestran los tiempos transcurridos, es inútil intentar implementar una función de eliminación utilizando índices definidos por grep o por mapas. Simplemente grep-remove directamente.
Antes de probar, pensaba que "map1" sería el más eficiente ... Supongo que debería confiar más en Benchmark. ;-)
fuente
Si conoce el índice de la matriz, puede eliminarlo () . La diferencia entre splice () y delete () es que delete () no vuelve a numerar los elementos restantes de la matriz.
fuente
Un código similar que escribí una vez para eliminar cadenas que no comienzan con SB.1 de una matriz de cadenas
my @adoSymbols=('SB.1000','RT.10000','PC.10000'); ##Remove items from an array from backward for(my $i=$#adoSymbols;$i>=0;$i--) { unless ($adoSymbols[$i] =~ m/^SB\.1/) {splice(@adoSymbols,$i,1);} }
fuente
Simplemente puede hacer esto:
my $input_Color = 'Green'; my @array = qw(Red Blue Green Yellow Black); @array = grep {!/$input_Color/} @array; print "@array";
fuente