Perl 해시의 키를 반복하는 가장 안전한 방법은 무엇입니까?perl


Answers

each 을 사용할 때주의해야 할 한 가지는 해시에 "상태"를 추가하는 부작용이 있다는 것입니다 (해시는 "다음"키가 무엇인지 기억해야합니다). 위에 게시 된 스 니펫과 같은 코드를 사용하면 한 번에 전체 해시를 반복하므로 일반적으로 문제가되지 않습니다. 그러나 each 키를 처리하기 전에 while ... each 루프를 사용하여 last 또는 return while ... each 과 같은 명령문을 사용하여 while ... each 루프를 종료 할 때 문제를 추적 할 수 있습니다 (경험적으로 말하면).

이 경우 해시는 이미 반환 된 키를 기억하고 다음 번에 each 을 사용할 때 (아마도 관련이없는 전체 코드에서)이 위치에서 계속됩니다.

예:

my %hash = ( foo => 1, bar => 2, baz => 3, quux => 4 );

# find key 'baz'
while ( my ($k, $v) = each %hash ) {
    print "found key $k\n";
    last if $k eq 'baz'; # found it!
}

# later ...

print "the hash contains:\n";

# iterate over all keys:
while ( my ($k, $v) = each %hash ) {
    print "$k => $v\n";
}

인쇄 내용 :

found key bar
found key baz
the hash contains:
quux => 4
foo => 1

"bar"와 "baz"키는 어떻게 되었습니까? 여전히 존재하지만 두 번째 키는 첫 번째 키가 중단 된 곳에서 시작하고 해시 끝에 도달하면 중지되므로 두 번째 루프에서 키를 볼 수 없습니다.

Question

내가 (키, 값) 쌍을 가진 Perl 해시를 가지고 있다면, 모든 키를 반복하는 기본 방법은 무엇입니까? each 방법을 사용하면 의도하지 않은 부작용이 생길 수 있다고 들었습니다. 그래서, 그게 사실이고, 다음 두 가지 방법 중 가장 좋은 방법인가, 아니면 더 좋은 방법이 있습니까?

# Method 1
while (my ($key, $value) = each(%hash)) {
    # Something
}

# Method 2
foreach my $key (keys(%hash)) {
    # Something
}



각 구문을 사용하면 키 집합 전체가 동시에 생성되지 않습니다. 수백만 개의 행이있는 데이터베이스에 연결된 해시를 사용하는 경우 중요 할 수 있습니다. 한 번에 전체 키 목록을 생성하고 실제 메모리를 소모하지 않으려 고합니다. 루프가 시작되기 전에 키가 실제로 전체 배열을 생성하는 반면이 경우 각각은 반복자 역할을합니다.

그래서, "각"실제 사용의 유일한 장소는 해시가 매우 클 때입니다 (사용 가능한 메모리와 비교). 이는 핸드 헬드 데이터 수집 디바이스 나 메모리가 적은 프로그램을 프로그래밍하지 않는 한 해시 자체가 메모리 자체에 저장되지 않는 경우에만 발생할 가능성이 높습니다.

메모리가 문제가되지 않는다면 일반적으로 맵 또는 키 패러다임이 더 유용하고 읽기 쉬운 패러다임입니다.




이 주제에 대한 몇 가지 잡다한 생각 :

  1. 해시 반복자 자체에 대해 안전하지 않은 요소는 없습니다. 안전하지 않은 것은 해시 키를 반복하는 동안 해시 키를 수정하는 것입니다. (값을 변경하는 것이 안전합니다.) 유일한 부가적인 부작용은 values 이 별칭을 반환한다는 것입니다. 즉, values 을 수정하면 해시의 내용이 수정됩니다. 이것은 의도적으로 설계 되었기 때문에 일부 상황에서는 원하는 결과가 아닐 수도 있습니다.
  2. John의 대답 은 한 가지 예외가 있습니다. 해시를 반복하는 동안 키를 추가하는 것이 안전하지 않다는 문서가 분명합니다. 일부 데이터 세트에서는 작동하지만 해시 순서에 따라 다른 데이터 세트에서는 실패합니다.
  3. 이미 언급했듯이 each 키가 반환 한 마지막 키를 삭제하는 것이 안전합니다. keys 가 목록을 반환하는 동안 each 반복자로 keyseach 사실이 아닙니다 .



나는 보통 keys 사용하고, 내가 마지막으로 사용하거나 each 의 사용법을 읽을 때를 생각할 수 없다.

루프에서 수행중인 작업에 따라 map 잊지 마세요.

map { print "$_ => $hash{$_}\n" } keys %hash;