potrzebne do góry usuń wszystkie pozycje nie będące plikami z listy katalogów, a "array = grep {-f $ _} tablica" działało dla mnie jak urok :)
taiko
Odpowiedzi:
87
Użyj złącza, jeśli znasz już indeks elementu, który chcesz usunąć.
Grep działa, jeśli szukasz.
Jeśli musisz wykonać wiele z tych czynności, uzyskasz znacznie lepszą wydajność, jeśli będziesz przechowywać tablicę w kolejności posortowanej, ponieważ możesz wtedy przeprowadzić wyszukiwanie binarne, aby znaleźć niezbędny indeks.
Jeśli ma to sens w twoim kontekście, możesz rozważyć użycie „magicznej wartości” dla usuniętych rekordów, zamiast ich usuwania, aby zaoszczędzić na przenoszeniu danych - na przykład ustaw usunięte elementy na undef. Oczywiście ma to swoje własne problemy (jeśli potrzebujesz znać liczbę „aktywnych” elementów, musisz śledzić to osobno itp.), Ale może być warte zachodu w zależności od aplikacji.
Edytuj Właściwie teraz, gdy przyjrzę się po raz drugi - nie używaj powyższego kodu grep. Bardziej wydajne byłoby znalezienie indeksu elementu, który chcesz usunąć, a następnie użyj splice, aby go usunąć (kod, który masz, gromadzi wszystkie niepasujące wyniki ..)
my $index = 0;
$index++ until $arr[$index] eq 'foo';
splice(@arr, $index, 1);
Spowoduje to usunięcie pierwszego wystąpienia. Usunięcie wszystkich wystąpień jest bardzo podobne, z tym wyjątkiem, że będziesz chciał uzyskać wszystkie indeksy za jednym razem:
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
Resztę pozostawiamy jako ćwiczenie dla czytelnika - pamiętaj, że tablica zmienia się w miarę jej łączenia!
Edit2 John Siracusa poprawnie wskazał, że mam błąd w moim przykładzie .. naprawiony, przepraszam za to.
jeśli ciąg nie zostanie znaleziony, pętla utknie, więc mój $ index = 0; my $ count = skalar @arr; $ index ++ aż do $ arr [$ index] eq 'foo' lub $ index == $ count; splice (@arr, $ index, 1);
Amir.F
1
lub my ($index) = grep { $arr[$_] eq 'foo' } 0..$#arr; if (defined $index) {splice(@arr, $index, 1); }- na pierwszy mecz
Reflective
13
splice usunie element (y) tablicy według indeksu. Użyj grep, jak w przykładzie, do wyszukiwania i usuwania.
Dzięki, Spoulson. Nie mam indeksów, które muszę usunąć, więc musiałem uciec się do grepa.
user21246
8
Czy to jest coś, co będziesz robić często? Jeśli tak, możesz rozważyć inną strukturę danych. Grep za każdym razem przeszuka całą tablicę, a duża tablica może być dość kosztowna. Jeśli problemem jest szybkość, możesz zamiast tego rozważyć użycie skrótu.
W twoim przykładzie kluczem byłaby liczba, a wartością byłaby liczba elementów tej liczby.
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
do
my @del_indexes = reverse(grep { $arr[$_] eq 'foo' } 0..$#arr);
Pozwala to uniknąć problemu z przenumerowaniem tablicy, usuwając najpierw elementy z tyłu tablicy. Umieszczenie splice () w pętli foreach czyści @arr. Stosunkowo proste i czytelne ...
Szczególnie podoba mi się logika i elegancja tego podejścia.
Keve,
Tak, rzeczywiście, możesz nawet napisać to jako jednolinijkowy: @arr = @arr[grep ...]co szczególnie mi się podoba. Nie jestem pewien, na ile jest skuteczny, ale zacznę go używać, ponieważ nie może być gorszy niż inne rozwiązania.
soger
3
Myślę, że twoje rozwiązanie jest najprostsze i najbardziej łatwe do utrzymania.
Reszta postu dokumentuje trudność przekształcania testów elementów w spliceprzesunięcia. W ten sposób jest to pełniejsza odpowiedź.
Przyjrzyj się bezwładnościom, przez które musisz przejść, aby mieć wydajny (tj. Jednoprzebiegowy) algorytm przekształcający testy elementów listy w indeksy. I wcale nie jest to takie intuicyjne.
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;
}
Usuń wartość tablicy prawdopodobnie będzie przestarzała (zobacz dokument)
e2-e4
3
to po prostu usuwa wartość przechowywaną w tym indeksie tablicy. przynajmniej w mojej wersji perla, (5.14)
Rooster
To naprawdę NIE usuwa tego, co myślisz. Usuwa tylko wartość, czyniąc ją undef. Poza tym z dokumentu połączonego przez ringø: „OSTRZEŻENIE: Odradza się wywoływanie funkcji usuwania wartości tablicowych. Pojęcie usuwania lub sprawdzania istnienia elementów tablicy Perla nie jest spójne koncepcyjnie i może prowadzić do zaskakującego zachowania”. (poprzedni akapit w dokumencie zawiera wszystkie krwawe szczegóły).
mivk
2
Usuń wszystkie wystąpienia „coś”, jeśli tablica.
Na podstawie odpowiedzi 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);
Za każdym razem, gdy usuniemy indeks z @arr, następnym poprawnym indeksem do usunięcia będzie $_-current_loop_step.
undef ustawia wartość elementu na null. Łączna liczba elementów (rozmiar) nadal jest taka sama.
Boontawee Home
1
@BoontaweeHome, grepna końcu je usuwa.
Deanna
1
Aby mieć pewność, że przeprowadziłem testy porównawcze grep i map, najpierw wyszukując indeksy dopasowanych elementów (tych do usunięcia), a następnie bezpośrednio usuwając elementy przez grep bez wyszukiwania indeksów. Wydaje mi się, że pierwsze rozwiązanie zaproponowane przez Sama podczas zadawania pytania było już najszybsze.
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;
},
});
Wynik to:
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
Jak pokazują czasy, które upłynęły, próba implementacji funkcji usuwania przy użyciu indeksów zdefiniowanych przez grep lub map jest bezcelowa. Po prostu grep-remove bezpośrednio.
Przed testami myślałem, że "map1" będzie najbardziej wydajna ... Chyba częściej powinienem polegać na Benchmarku. ;-)
Jeśli znasz indeks tablicy, możesz go usunąć () . Różnica między splice () i delete () polega na tym, że metoda delete () nie przenumeruje pozostałych elementów tablicy.
Właściwie miałem na myśli renumerację, co według Perldoca, splice () tak.
Powerlord
0
Podobny kod, który kiedyś napisałem, aby usunąć ciągi nie zaczynające się od SB.1 z tablicy ciągów
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);}
}
Odpowiedzi:
Użyj złącza, jeśli znasz już indeks elementu, który chcesz usunąć.
Grep działa, jeśli szukasz.
Jeśli musisz wykonać wiele z tych czynności, uzyskasz znacznie lepszą wydajność, jeśli będziesz przechowywać tablicę w kolejności posortowanej, ponieważ możesz wtedy przeprowadzić wyszukiwanie binarne, aby znaleźć niezbędny indeks.
Jeśli ma to sens w twoim kontekście, możesz rozważyć użycie „magicznej wartości” dla usuniętych rekordów, zamiast ich usuwania, aby zaoszczędzić na przenoszeniu danych - na przykład ustaw usunięte elementy na undef. Oczywiście ma to swoje własne problemy (jeśli potrzebujesz znać liczbę „aktywnych” elementów, musisz śledzić to osobno itp.), Ale może być warte zachodu w zależności od aplikacji.
Edytuj Właściwie teraz, gdy przyjrzę się po raz drugi - nie używaj powyższego kodu grep. Bardziej wydajne byłoby znalezienie indeksu elementu, który chcesz usunąć, a następnie użyj splice, aby go usunąć (kod, który masz, gromadzi wszystkie niepasujące wyniki ..)
my $index = 0; $index++ until $arr[$index] eq 'foo'; splice(@arr, $index, 1);
Spowoduje to usunięcie pierwszego wystąpienia. Usunięcie wszystkich wystąpień jest bardzo podobne, z tym wyjątkiem, że będziesz chciał uzyskać wszystkie indeksy za jednym razem:
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
Resztę pozostawiamy jako ćwiczenie dla czytelnika - pamiętaj, że tablica zmienia się w miarę jej łączenia!
Edit2 John Siracusa poprawnie wskazał, że mam błąd w moim przykładzie .. naprawiony, przepraszam za to.
źródło
my ($index) = grep { $arr[$_] eq 'foo' } 0..$#arr; if (defined $index) {splice(@arr, $index, 1); }
- na pierwszy meczsplice usunie element (y) tablicy według indeksu. Użyj grep, jak w przykładzie, do wyszukiwania i usuwania.
źródło
Czy to jest coś, co będziesz robić często? Jeśli tak, możesz rozważyć inną strukturę danych. Grep za każdym razem przeszuka całą tablicę, a duża tablica może być dość kosztowna. Jeśli problemem jest szybkość, możesz zamiast tego rozważyć użycie skrótu.
W twoim przykładzie kluczem byłaby liczba, a wartością byłaby liczba elementów tej liczby.
źródło
jeśli się zmienisz
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
do
my @del_indexes = reverse(grep { $arr[$_] eq 'foo' } 0..$#arr);
Pozwala to uniknąć problemu z przenumerowaniem tablicy, usuwając najpierw elementy z tyłu tablicy. Umieszczenie splice () w pętli foreach czyści @arr. Stosunkowo proste i czytelne ...
foreach $item (@del_indexes) { splice (@arr,$item,1); }
źródło
Zamiast splicingu można użyć wycinania tablic. Grep, aby zwrócić indeksy, które chcesz zachować i użyć wycinania:
my @arr = ...; my @indicesToKeep = grep { $arr[$_] ne 'foo' } 0..$#arr; @arr = @arr[@indiciesToKeep];
źródło
@arr = @arr[grep ...]
co szczególnie mi się podoba. Nie jestem pewien, na ile jest skuteczny, ale zacznę go używać, ponieważ nie może być gorszy niż inne rozwiązania.Myślę, że twoje rozwiązanie jest najprostsze i najbardziej łatwe do utrzymania.
Reszta postu dokumentuje trudność przekształcania testów elementów w
splice
przesunięcia. W ten sposób jest to pełniejsza odpowiedź.Przyjrzyj się bezwładnościom, przez które musisz przejść, aby mieć wydajny (tj. Jednoprzebiegowy) algorytm przekształcający testy elementów listy w indeksy. I wcale nie jest to takie intuicyjne.
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; }
źródło
Używam:
delete $array[$index];
Usuń Perldoc .
źródło
undef
. Poza tym z dokumentu połączonego przez ringø: „OSTRZEŻENIE: Odradza się wywoływanie funkcji usuwania wartości tablicowych. Pojęcie usuwania lub sprawdzania istnienia elementów tablicy Perla nie jest spójne koncepcyjnie i może prowadzić do zaskakującego zachowania”. (poprzedni akapit w dokumencie zawiera wszystkie krwawe szczegóły).Usuń wszystkie wystąpienia „coś”, jeśli tablica.
Na podstawie odpowiedzi 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);
Za każdym razem, gdy usuniemy indeks z
@arr
, następnym poprawnym indeksem do usunięcia będzie$_-current_loop_step
.źródło
Do usunięcia można użyć grupy nieprzechwytywanej i listy elementów rozdzielanych pionami.
perl -le '@ar=(1 .. 20);@x=(8,10,3,17);$x=join("|",@x);@ar=grep{!/^(?:$x)$/o} @ar;print "@ar"'
źródło
Najlepsze, jakie znalazłem, to połączenie „undef” i „grep”:
foreach $index ( @list_of_indexes_to_be_skiped ) { undef($array[$index]); } @array = grep { defined($_) } @array;
To załatwia sprawę! Federico
źródło
grep
na końcu je usuwa.Aby mieć pewność, że przeprowadziłem testy porównawcze grep i map, najpierw wyszukując indeksy dopasowanych elementów (tych do usunięcia), a następnie bezpośrednio usuwając elementy przez grep bez wyszukiwania indeksów. Wydaje mi się, że pierwsze rozwiązanie zaproponowane przez Sama podczas zadawania pytania było już najszybsze.
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; }, });
Wynik to:
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
Jak pokazują czasy, które upłynęły, próba implementacji funkcji usuwania przy użyciu indeksów zdefiniowanych przez grep lub map jest bezcelowa. Po prostu grep-remove bezpośrednio.
Przed testami myślałem, że "map1" będzie najbardziej wydajna ... Chyba częściej powinienem polegać na Benchmarku. ;-)
źródło
Jeśli znasz indeks tablicy, możesz go usunąć () . Różnica między splice () i delete () polega na tym, że metoda delete () nie przenumeruje pozostałych elementów tablicy.
źródło
Podobny kod, który kiedyś napisałem, aby usunąć ciągi nie zaczynające się od SB.1 z tablicy ciągów
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);} }
źródło
Możesz to po prostu zrobić:
my $input_Color = 'Green'; my @array = qw(Red Blue Green Yellow Black); @array = grep {!/$input_Color/} @array; print "@array";
źródło