문제

많은 차원의 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 또는 이와 유사한 해시를 묶지 않으면 해시 요소가 트래 버스가 될지 예측할 수 없습니다. 다시 많은 작업을 수행하려면 트리 모듈을 권장합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top