Perl에서 다차원 해시를 가로 지르고 있습니다
-
03-07-2019 - |
문제
많은 차원의 Perl에 해시 (또는 해시에 대한 참조)가 있고 모든 값에 걸쳐 반복하려는 경우 가장 좋은 방법은 무엇입니까? 다시 말해서, 우리가 $ f-> {$ x} {$ y}가 있다면, 나는
foreach ($x, $y) (deep_keys %{$f})
{
}
대신에
foreach $x (keys %f)
{
foreach $y (keys %{$f->{$x})
{
}
}
해결책
다음은 옵션입니다. 이것은 임의로 깊은 해시를 위해 작동합니다.
sub deep_keys_foreach
{
my ($hashref, $code, $args) = @_;
while (my ($k, $v) = each(%$hashref)) {
my @newargs = defined($args) ? @$args : ();
push(@newargs, $k);
if (ref($v) eq 'HASH') {
deep_keys_foreach($v, $code, \@newargs);
}
else {
$code->(@newargs);
}
}
}
deep_keys_foreach($f, sub {
my ($k1, $k2) = @_;
print "inside deep_keys, k1=$k1, k2=$k2\n";
});
다른 팁
1 단계 : 바퀴를 재발 명하지 마십시오 :)
빨리 CPAN에서 검색하십시오 엄청나게 유용합니다 데이터 :: 걷기. 각 노드를 처리하기 위해 서브 루틴을 정의하면 정렬됩니다.
use Data::Walk;
my $data = { # some complex hash/array mess };
sub process {
print "current node $_\n";
}
walk \&process, $data;
그리고 밥은 당신의 삼촌입니다. 걸어 다니기 위해 해시를 통과하려면 참조를 전달해야합니다. Perldoc Perlref), 다음과 같이 (그렇지 않으면 해시 키도 처리하고 처리 할 것입니다!) :
walk \&process, \%hash;
보다 포괄적 인 솔루션 (CPAN에서 언뜻보기가 어렵음)을 위해 사용하십시오. 데이터 :: 방문자 :: 콜백 또는 부모 모듈 - 이것은 당신이하는 일을 더 잘 통제 할 수있는 이점이 있으며 (여분의 스트리트 크레디트를 위해) Moose를 사용하여 작성됩니다.
마치 마치 마치 나에게 들립니다 데이터 :: 다이버 또는 데이터 :: 방문자 당신을위한 좋은 접근법입니다.
Perl 목록과 해시는 가지다 치수는 다차원적일 수 없습니다. 당신이 ~할 수 있다 다른 해시 또는 목록을 참조하도록 설정된 해시 항목입니다. 이것은 가짜 다차원 구조를 만드는 데 사용될 수 있습니다.
이것을 깨닫게되면 상황이 쉬워집니다. 예를 들어:
sub f($) {
my $x = shift;
if( ref $x eq 'HASH' ) {
foreach( values %$x ) {
f($_);
}
} elsif( ref $x eq 'ARRAY' ) {
foreach( @$x ) {
f($_);
}
}
}
물론 구조를 가로 지르는 것 외에해야 할 다른 일을 추가하십시오.
필요한 일을하는 멋진 방법 중 하나는 내부에서 호출되도록 코드 참조를 전달하는 것입니다. 서브 프로토 타이핑을 사용하면 통화가 Perl의 GREP 및 MAP 기능처럼 보이게 할 수도 있습니다.
항상 모든 주요 값을 가지고 있거나 개별 레벨에 별도의 배열로 액세스 할 필요가 없다면 다차원 배열 퍼지를 퍼지 할 수도 있습니다.
$arr{"foo",1} = "one";
$arr{"bar",2} = "two";
while(($key, $value) = each(%arr))
{
@keyValues = split($;, $key);
print "key = [", join(",", @keyValues), "] : value = [", $value, "]\n";
}
이것은 첨자 분리기 "$;"를 사용합니다. 키의 여러 값에 대한 분리기로.
당신이 묘사하는 의미를 얻을 방법이 없습니다. foreach
한 번에 하나의 요소를 목록 위에 반복합니다. 당신은 있어야합니다 deep_keys
대신 LOL (목록 목록)을 반환하십시오. 심지어 임의의 데이터 구조의 일반적인 경우에는 작동하지 않습니다. 다양한 수준의 하위 하시가있을 수 있으며 일부 레벨은 배열 참조 등이 될 수 있습니다.
이 작업을 수행하는 Perlish 방법은 임의의 데이터 구조를 걸을 수있는 함수를 작성하고 각 "리프"(즉, 비 참조 값)에 콜백을 적용하는 것입니다. Bmdhacks의 답변 출발점입니다. 정확한 함수는 각 레벨에서 원하는 작업에 따라 다릅니다. 당신이 관심을 갖는 모든 것이 잎 값이라면 꽤 간단합니다. 열쇠, 지수 등에 관심이 있으면 상황이 더욱 복잡해집니다.
값으로 작동하는 것이 쉽지만 키에서 작동하려면 레벨이 복구 가능한 방법에 대한 사양이 필요합니다.
ㅏ. 예를 들어 키를 지정할 수 있습니다 "$level1_key.$level2_key.$level3_key"
-또는 레벨을 나타내는 모든 분리기.
비. 또는 키 목록을 가질 수 있습니다.
후자를 추천합니다.
레벨은 이해할 수 있습니다
@$key_stack
그리고 가장 지역 키는입니다
$key_stack->[-1]
.경로는 다음과 같이 재구성 할 수 있습니다.
join( '.', @$key\_stack )
암호:
use constant EMPTY_ARRAY => [];
use strict;
use Scalar::Util qw<reftype>;
sub deep_keys (\%) {
sub deeper_keys {
my ( $key_ref, $hash_ref ) = @_;
return [ $key_ref, $hash_ref ] if reftype( $hash_ref ) ne 'HASH';
my @results;
while ( my ( $key, $value ) = each %$hash_ref ) {
my $k = [ @{ $key_ref || EMPTY_ARRAY }, $key ];
push @results, deeper_keys( $k, $value );
}
return @results;
}
return deeper_keys( undef, shift );
}
foreach my $kv_pair ( deep_keys %$f ) {
my ( $key_stack, $value ) = @_;
...
}
이것은 Perl 5.10에서 테스트되었습니다.
트리 데이터를 사용하여 두 레벨이 넘는 수준이 높아지고 그 나무를 걷고 싶어한다면 먼저 필요한 모든 것을 다시 구현할 계획이라면 자신을 위해 많은 일을 할 것이라고 생각해야합니다. 사용 가능한 좋은 대안이 많이있을 때 해시 해시 해시 해시에서 수동으로 수행하십시오 ("트리"에 대한 CPAN 검색).
귀하의 데이터 요구 사항이 실제로 무엇인지 알지 못하고 맹목적으로 당신을 트리 튜토리얼 :: dag_node 당신을 시작하기 위해.
즉, Axeman은 맞습니다. 해시 워크는 재귀로 가장 쉽게 이루어집니다. 다음은 해시 해시 해시로 문제를 해결해야한다고 생각되면 시작하는 예입니다.
#!/usr/bin/perl use strict; use warnings; my %hash = ( "toplevel-1" => { "sublevel1a" => "value-1a", "sublevel1b" => "value-1b" }, "toplevel-2" => { "sublevel1c" => { "value-1c.1" => "replacement-1c.1", "value-1c.2" => "replacement-1c.2" }, "sublevel1d" => "value-1d" } ); hashwalk( \%hash ); sub hashwalk { my ($element) = @_; if( ref($element) =~ /HASH/ ) { foreach my $key (keys %$element) { print $key," => \n"; hashwalk($$element{$key}); } } else { print $element,"\n"; } }
출력 :
toplevel-2 => sublevel1d => value-1d sublevel1c => value-1c.2 => replacement-1c.2 value-1c.1 => replacement-1c.1 toplevel-1 => sublevel1a => value-1a sublevel1b => value-1b
타이 :: ixhash 또는 이와 유사한 해시를 묶지 않으면 해시 요소가 트래 버스가 될지 예측할 수 없습니다. 다시 많은 작업을 수행하려면 트리 모듈을 권장합니다.