[arrays] 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);
}


답변

스 플라이 싱 대신 어레이 슬라이싱을 사용할 수 있습니다. 유지하려는 인덱스를 반환하고 슬라이싱을 사용하려면 Grep :

my @arr = ...;
my @indicesToKeep = grep { $arr[$_] ne 'foo' } 0..$#arr;
@arr = @arr[@indiciesToKeep];


답변

귀하의 솔루션이 가장 간단하고 유지 관리가 용이하다고 생각합니다.

나머지 포스트에서는 요소에 대한 테스트를 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;
}


답변

나는 사용한다:

delete $array[$index];

Perldoc 삭제 .