arrays - lista - splice perl español
¿Cuál es la mejor manera de eliminar un valor de una matriz en Perl? (12)
Creo que su solución es la más simple y más fácil de mantener.
El resto de la publicación documenta la dificultad de convertir las pruebas en elementos en compensaciones de splice
. Por lo tanto, lo que es una respuesta más completa .
Observe los giros que debe realizar para tener un algoritmo eficiente (es decir, de un solo paso) para convertir las pruebas en 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;
}
La matriz tiene muchos datos y necesito eliminar dos elementos.
A continuación se muestra el fragmento de código que estoy usando,
my @array = (1,2,3,4,5,5,6,5,4,9);
my $element_omitted = 5;
@array = grep { $_ != $element_omitted } @array;
¿Esto es algo que vas a hacer mucho? Si es así, es posible que desee considerar una estructura de datos diferente. Grep buscará todo el conjunto cada vez y para un conjunto grande podría ser bastante costoso. Si la velocidad es un problema, entonces puede 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.
Eliminar 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 eliminamos el índice de @arr
, el siguiente índice correcto para eliminar será $_-current_loop_step
.
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
Podría utilizar el corte de matriz en lugar de empalmar. Grep para devolver los índices que desea conservar y usar slicing:
my @arr = ...;
my @indicesToKeep = grep { $arr[$_] ne ''foo'' } 0..$#arr;
@arr = @arr[@indiciesToKeep];
Puede usar el grupo que no captura y una lista de elementos de delimitación de tuberías para eliminar.
perl -le ''@ar=(1 .. 20);@x=(8,10,3,17);$x=join("|",@x);@ar=grep{!/^(?:$x)$/o} @ar;print "@ar"''
Si conoce el índice de matriz, puede delete . La diferencia entre splice () y delete () es que delete () no renumera los elementos restantes de la matriz.
Un código similar que una vez escribí para eliminar cadenas que no comienzan con SB.1 desde 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);}
}
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 ordenada, ya que 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: configure los elementos eliminados en undef, por ejemplo. Naturalmente, esto tiene sus propios problemas (si necesita saber la cantidad de elementos "activos", necesita hacer un seguimiento de los mismos por separado, etc.), pero puede valer la pena dependiendo de su aplicación.
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 usar el empalme para eliminarlo (el código que ha acumulado todos los resultados no coincidentes ...)
my $index = 0;
$index++ until $arr[$index] eq ''foo'';
splice(@arr, $index, 1);
Eso eliminará la primera ocurrencia. Eliminar todas las ocurrencias es muy similar, excepto que deseará obtener todos los índices en una sola pasada:
my @del_indexes = grep { $arr[$_] eq ''foo'' } 0..$#arr;
El resto queda como un 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 ... solucionado, lo siento.
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 renumeración de matriz al eliminar elementos de la parte posterior de la matriz primero. Poner un empalme () en un bucle foreach limpia @arr. Relativamente simple y legible ...
foreach $item (@del_indexes) {
splice (@arr,$item,1);
}
splice eliminará elementos de matriz por índice. Use grep, como en su ejemplo, para buscar y eliminar.