Perl의 배열에서 값을 삭제하는 가장 좋은 방법은 무엇입니까?
배열에는 많은 데이터가 있으며 두 개의 요소를 삭제해야합니다.
아래는 내가 사용중인 코드 스 니펫입니다.
my @array = (1,2,3,4,5,5,6,5,4,9);
my $element_omitted = 5;
@array = grep { $_ != $element_omitted } @array;
삭제할 요소의 색인을 이미 알고있는 경우 스플 라이스를 사용하십시오.
검색하는 경우 Grep이 작동합니다.
이러한 작업을 많이 수행해야하는 경우 배열을 정렬 된 순서로 유지하면 이진 검색을 수행하여 필요한 인덱스를 찾을 수 있으므로 훨씬 더 나은 성능을 얻을 수 있습니다.
상황에 맞다면 삭제 된 레코드에 "매직 값"을 사용하는 것이 아니라 데이터 이동을 저장하기 위해 삭제하는 것을 고려할 수 있습니다. 예를 들어 삭제 된 요소를 undef로 설정합니다. 당연히 여기에는 자체 문제가 있지만 ( "라이브"요소의 수를 알아야하는 경우 별도로 추적해야하는 등) 응용 프로그램에 따라 문제가 될 수 있습니다.
실제로 편집 해 보았습니다. 위의 grep 코드를 사용하지 마십시오. 삭제하려는 요소의 색인을 찾은 다음 스플 라이스를 사용하여 삭제하는 것이 더 효율적일 것입니다. (당신이 가진 코드는 일치하지 않는 모든 결과를 축적합니다.)
my $index = 0;
$index++ until $arr[$index] eq 'foo';
splice(@arr, $index, 1);
첫 번째 항목이 삭제됩니다. 모든 항목을 삭제하는 것은 한 번에 모든 인덱스를 가져 오는 것을 제외하고는 매우 유사합니다.
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
나머지는 독자를위한 연습 문제로 남겨 둡니다. 연결하면 어레이가 변경된다는 점을 기억하십시오!
Edit2 John Siracusa는 내 예제에 버그가 있다고 정확하게 지적했습니다. 수정되었습니다. 죄송합니다.
스플 라이스 는 인덱스로 배열 요소를 제거합니다. 예제에서와 같이 grep을 사용하여 검색하고 제거하십시오.
이것은 당신이 많이 할 일입니까? 그렇다면 다른 데이터 구조를 고려할 수 있습니다. Grep은 매번 전체 어레이를 검색 할 것이며 대형 어레이의 경우 비용이 많이들 수 있습니다. 속도가 문제인 경우 대신 해시를 사용하는 것이 좋습니다.
귀하의 예에서 키는 숫자이고 값은 해당 숫자의 요소 수입니다.
변경하면
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
...에
my @del_indexes = reverse(grep { $arr[$_] eq 'foo' } 0..$#arr);
이렇게하면 먼저 배열 뒷면에서 요소를 제거하여 배열 번호 재 지정 문제를 방지 할 수 있습니다. splice ()를 foreach 루프에 넣으면 @arr가 정리됩니다. 비교적 간단하고 읽기 쉬운 ...
foreach $item (@del_indexes) {
splice (@arr,$item,1);
}
귀하의 솔루션이 가장 간단하고 유지 관리가 용이하다고 생각합니다.
나머지 포스트에서는 요소에 대한 테스트를 splice
오프셋 으로 전환하는 것이 얼마나 어려운지 설명 합니다. 따라서 더 완전한 대답으로 만듭니다.
목록 항목에 대한 테스트를 인덱스로 전환하는 효율적인 (예 : 1 회 통과) 알고리즘을 갖기 위해 거쳐야 하는 회전 을 살펴보십시오 . 그리고 그것은 전혀 직관적이지 않습니다.
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;
}
스 플라이 싱 대신 어레이 슬라이싱을 사용할 수 있습니다. 유지하려는 인덱스를 반환하고 슬라이싱을 사용하려면 Grep :
my @arr = ...;
my @indicesToKeep = grep { $arr[$_] ne 'foo' } 0..$#arr;
@arr = @arr[@indiciesToKeep];
나는 사용한다:
delete $array[$index];
Perldoc 삭제 .
배열 인 경우 'something'항목을 모두 삭제합니다.
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);
에서 색인을 제거 할 때마다 @arr
삭제할 다음 올바른 색인은입니다 $_-current_loop_step
.
비 캡처 그룹 및 제거 할 항목의 파이프 delim 목록을 사용할 수 있습니다.
perl -le '@ar=(1 .. 20);@x=(8,10,3,17);$x=join("|",@x);@ar=grep{!/^(?:$x)$/o} @ar;print "@ar"'
내가 찾은 최고는 "undef"와 "grep"의 조합이었습니다.
foreach $index ( @list_of_indexes_to_be_skiped ) {
undef($array[$index]);
}
@array = grep { defined($_) } @array;
그게 트릭입니다! 페데리코
Just to be sure I have benchmarked grep and map solutions, first searching for indexes of matched elements (those to remove) and then directly removing the elements by grep without searching for the indexes. I appears that the first solution proposed by Sam when asking his question was already the fastest.
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;
},
});
The result is:
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
As shown by elapsed times, it's useless to try to implement a remove function using either grep or map defined indexes. Just grep-remove directly.
Before testing I was thinking "map1" would be the most efficient... I should more often rely on Benchmark I guess. ;-)
If you know the array index, you can delete() it. The difference between splice() and delete() is that delete() does not renumber the remaining elements of the array.
A similar code I once wrote to remove strings not starting with SB.1 from an array of strings
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);}
}
You can simply do this:
my $input_Color = 'Green';
my @array = qw(Red Blue Green Yellow Black);
@array = grep {!/$input_Color/} @array;
print "@array";
'Development Tip' 카테고리의 다른 글
Matplotlib의 인라인 레이블 (0) | 2020.10.14 |
---|---|
버튼 또는 필드 셋 요소에서 작동하지 않는 Flexbox (0) | 2020.10.14 |
CSS : 하단 및 중앙에 고정 (0) | 2020.10.14 |
Eclipse의 메모리 사용량을 줄이는 방법은 무엇입니까? (0) | 2020.10.14 |
Javascript로 SVG 요소에 액세스하는 방법 (0) | 2020.10.14 |