Annoying hash in perl

Perl 에서 귀 찮 은 것 은 hash 의 변화 라 고 생각 합 니 다. 여기 서 복잡 한 변 화 를 드 립 니 다.
 산열 된 배열
만약 기록 이 한 무더기 있다 면, 순서대로 그것들 을 방문 하고 싶 으 며, 모든 기록 자체 에 키 / 수치 가 포함 되 어 있 으 면, 흩 어 진 배열 이 매우 유용 하 다.이 장 에 서 는 산열 된 배열 이 다른 구조 보다 조금 적다.
 
1. 산열 된 배열 을 구성한다.
다음 방법 으로 익명 으로 흩 어 진 배열 을 만 들 수 있 습 니 다:
 
   @AoH = (
      {
         husband => "barney",
         wife    => "betty",
         son    => "bamm bamm",   
      },
      {
         husband => "george",
         wife    => "jane",
         son    => "elroy",
      },
      {
         husband => "homer",
         wife    => "marge",
         son    => "bart",
      },
   );

 
 
배열 에 다른 해시 를 추가 하려 면 간단하게 말 할 수 있 습 니 다.
 
push @AoH, { husband => "fred", wife => "wilma", daughter => "pebbles" };

 
 
 
2. 산열 을 만 드 는 배열
다음은 해시 배열 을 채 우 는 기술 입 니 다.다음 형식 을 파일 에서 읽 으 려 면:
 
   husband=fred friend=barney

다음 두 순환 중 하 나 를 사용 할 수 있 습 니 다.
 
   while (<>) {
      $rec = {};
      for $field ( split ) {
         ($key, $value) = split /=/, $field;
         $rec->{$key} = $value;
      }
      push @AoH, $rec;
   }

   while (<>) {
      push @AoH, { split /[\s=]+/ };
   }

 
 
키 프로 세 스 getnext_pair 키 / 수 치 를 되 돌려 줍 니 다. 다음 두 순환 중 하 나 를 이용 하여 @ AoH 를 채 울 수 있 습 니 다.
 
   while ( @fields = get_next_pari()) {
      push @AoH, {@fields};
   }

   while (<>) {
      push @AoH, { get_next_pair($_) };
   }

 
 
당신 은 아래 와 같이 기 존의 해시 에 새로운 구성원 을 추가 할 수 있 습 니 다.
 
   $AoH[0]{pet} = "dino";
   $AoH[2]{pet} = "santa's little helper";

 
 
 
3. 해시 에 접근 하고 인쇄 하 는 배열
다음 방법 으로 특정한 산열 의 수치 / 키 를 설정 할 수 있 습 니 다.
 
 
   
$AoH[0]{husband} = "fred";
 
 
 
두 번 째 배열 의 남편 (husband) 을 대문자 로 바 꾸 고 하나 로 바 꿔 야 합 니 다.
 
 
   $AoH[1]{husband} =~ s/(\w)/\u$1/;
 
 
 
당신 은 아래 의 방법 으로 모든 데 이 터 를 인쇄 할 수 있 습 니 다.
 
 
   for $href ( @AoH ) {
      print "{ ";
      for $role ( keys %$href ) {
         print "$role=$href->{$role} ";
      }
      print "}
"; }
 
 
인용 인쇄
 
 
   for $i ( 0 .. $#AoH ) {
      print "$i is { ";
      for $role ( keys %{ $AoH[$i] } ) {
         print "$role=$AoH[$i]{$role} ";
      }
      print "}
"; }
 
 
 
 산열
다 차원 의 산열 은 Perl 에서 가장 유연 한 내장 구조 이다.그것 은 마치 하나의 기록 을 연결 하 는 것 처럼 그 기록 자체 에 다른 기록 이 포함 되 어 있다.모든 단계 에서, 당신 은 이 산열 의 색인 을 하나의 문자열 (필요 할 때 발생) 로 만 듭 니 다.단, 해시 에 있 는 키 / 수 치 는 특정한 순서 로 나타 나 지 않 는 다 는 것 을 기억 하 세 요.당신 은 sort 함 수 를 사용 하여 당신 이 좋아 하 는 모든 순서 로 이 짝 을 검색 할 수 있 습 니 다.
 
1. 산열 을 구성 하 는 산열
다음 방법 으로 익명 산열 의 산열 을 만 들 수 있 습 니 다.
 
 
   %HoH = (
      flintstones => {
         husband => "fred",
         pal    => "barney",
      },
      jetsons => {
         husband => "george",
         wife    => "jane",
         "his boy" => "elroy",      #       
      },
      simpsons => {
         husband => "homer",
         wife    => "marge",
         kid     => "bart",
      },

   );
 
 
% HoH 에 다른 익명 의 해시 태 그 를 추가 하려 면 간단하게 말 할 수 있 습 니 다.
 
 
   $HoH{ mash } = {
      captain => "pierce",
      major   => "burns",
      corporal=> "radar",
   }
 
 
 
2 산열 의 산열 생 성
다음은 해시 하 나 를 채 우 는 해시 기법 입 니 다.다음 형식의 파일 에서 데 이 터 를 읽 으 려 면:
 
flintstones
husband=fred pal=barney wife=wilma pet=dino
 
다음 두 순환 중 하 나 를 사용 할 수 있 습 니 다.
 
 
   while( <> ){
      next unless s/^(.*?):\S*//;
      $who = $1;
      for $field ( split ) {
         ($key, $value) = split /=/, $field;
         $HoH{$who}{$key} = $value;
      }
   }

   while( <> ){
      next unless s/^(.*?):\S*//;
      $who = $1;
      $rec = {};
      $HoH{$who} = $rec;
      for $field ( split ) {
         ($key, $value) = split /=/, $field;
         $rec->{$key} = $value;
      }
   }
 
 
키 프로 세 스 getfamily 키 / 수치 목록 을 되 돌려 줍 니 다. 다음 세 가지 방법 중 하 나 를 가 져 와 서% HoH 를 채 울 수 있 습 니 다.
 
 
   for $group ("simpsons", "jetsons", "flintstones" ) {
      $HoH{$group} = {get_family($group)};
   }

   for $group ( "simpsons", "jetsons", "flintstones" ) {
      @members = get_family($group);
      $HoH{$group} = {@menbers};
   }

   sub hash_families {
      my @ret;
      for $group (@_) {
         push @ret, $group, {get_family($group)};
      }
      return @ret;
   }

   %HoH = hash_families( "simpsons", "jetsons", "flintstones" );
 
 
당신 은 아래 의 방법 으로 기 존의 해시 에 새로운 구성원 을 추가 할 수 있 습 니 다.
 
 
   %new_floks = (
      wife => "wilma",
      pet  => "dino",
   );

   for $what (keys %new_floks) {
      $HoH{flintstones}{$what} = $new_floks{$what};
   }
 
 
 
3 산열 에 접근 하고 인쇄 하 는 산열
키 / 수 치 를 아래 방법 으로 설정 할 수 있 습 니 다.
 
 
 
  $HoH{flintstones}{wife} = "wilma";
 
 
 
어떤 키 글자 / 수 치 를 대문자 로 바 꾸 려 면 이 요소 에 대한 교 체 를 적용 하 십시오.
 
 
  
 $HoH{jetsons}{'his boy'} =~ s/(\w)/\u$1/;
 
 
 
당신 은 전후 로 내외 층 의 해시 키 글 자 를 옮 겨 다 니 는 방법 으로 모든 가족 을 인쇄 할 수 있 습 니 다.
 
 
   for $family ( keys %HoH ) {
      print "$family: ";
      for $role ( keys %{ $HoH{$family} } ){
         print "$role=$person ";
      }
      print "
"; }
 
 
아주 큰 해시 에 서 는 each 를 사용 하여 키 와 수 치 를 동시에 검색 할 수 있 습 니 다. (이렇게 하면 정렬 을 피 할 수 있 습 니 다)
 
 
   while ( ($family, $roles) = each %HoH ) {
      print "$family: ";
      while ( ($role, $person) = each %$roles ) {
         print "$role=$person";
      }
      print "
"; }
 
 
(나 쁜 것 은, 저장 해 야 할 것 은 그 큰 해시 입 니 다. 그렇지 않 으 면 인쇄 출력 에서 원 하 는 것 을 영원히 찾 을 수 없습니다.) 다음 방법 으로 가족 을 정렬 한 다음 에 발 색 을 정렬 할 수 있 습 니 다.
 
 
   for $family ( sort keys %HoH ) {
      print "$family:  ";
      for $role ( sort keys %{ $HoH{$family} } ) {
         print "$role=$HoH{$family}{$role} ";
      }
      print "
"; }
 
 
가족 번호 에 따라 정렬 해 야 합 니 다 (ASCII 코드 (또는 utf 8 코드). 하나의 스칼라 환경 에서 keys 를 사용 할 수 있 습 니 다.
 
 
   for $family ( sort { keys %{$HoH{$a} } <=> keys %{$HoH{$b}}} keys %HoH ) {
      print "$family: ";
      for $role ( sort keys %{ $HoH{$family} } ) {
         print "$role=$HoH{$family}{$role};
      }
      print "
"; }
 
 
어떤 고정된 순서 로 한 가족 을 정렬 하려 면 모든 구성원 에 게 하나의 등급 을 부여 하여 실현 할 수 있다.
 
 
   $i = 0;
   for ( qw(husband wife son daughter pal pet) ) { $rank{$_} = ++$i }

   for $family ( sort { keys %{$HoH{$a} } <=> keys %{$HoH{$b}}} keys %HoH ) {
      print "$family: ";
      for $role ( sort { $rank{$a} <=> $rank{$b} } keys %{ $HoH{$family} }) {
         print "$role=$HoH{$family}{$role} ";
      }
   print "
"; }
 
 
 
 함수 의 산열
Perl 을 사용 하여 복잡 한 애플 리 케 이 션 이나 인터넷 서 비 스 를 쓸 때 사용자 에 게 많은 명령 을 만들어 서 사용 하도록 해 야 할 수도 있 습 니 다.이러한 프로그램 은 아래 와 같은 코드 로 사용자 의 선택 을 검사 한 다음 에 해당 하 는 동작 을 취 할 수 있 습 니 다.
 
 
if    ($cmd =~ /^exit$/i)     { exit }
elsif ($cmd =~ /^help$/i)     { show_help() }
elsif ($cmd =~ /^watch$/i)    { $watch = 1 }
elsif ($cmd =~ /^mail$/i)     { mail_msg($msg) }
elsif ($cmd =~ /^edit$/i)     { $edited++; editmsg($msg); }
elsif ($cmd =~ /^delete$/i)   { confirm_kill() }
else {
    warn "Unknown command: `$cmd'; Try `help' next time
"; }
 
 
또한 데이터 구조 에 지향 함수 의 인용 을 저장 할 수 있 습 니 다. 배열 이나 해시 에 대한 인용 을 저장 할 수 있 는 것 처럼:
 
 
%HoF = (                           # Compose a hash of functions
    exit    =>  sub { exit },
    help    =>  \&show_help,
    watch   =>  sub { $watch = 1 },
    mail    =>  sub { mail_msg($msg) },
    edit    =>  sub { $edited++; editmsg($msg); },
    delete  =>  \&confirm_kill,
);

if   ($HoF{lc $cmd}) { $HoF{lc $cmd}->() }   # Call function
else { warn "Unknown command: `$cmd'; Try `help' next time
" }
 
 
마지막 두 번 째 줄 에서 우 리 는 성명 의 명령 이름 (소문 자) 이 우리 의 '송환 표'% HoF 에 존재 하 는 지 확인 했다.만약 에 우리 가 응답 하 는 명령 을 호출 하 는 방법 은 해시 값 을 함수 로 하여 인용 을 풀 고 이 함수 에 빈 매개 변수 목록 을 전달 하 는 것 입 니 다.우 리 는 & {$HoF {lc $cmd} () 로 해시 값 을 인용 하거나 Perl 5.6 에서 간단하게 $HoF {lc $cmd} () 일 수 있 습 니 다.
 
 더욱 유연 한 기록
지금까지 우리 가 본 장 에서 본 것 은 모두 간단 하고 두 층 의 동 질 적 인 데이터 구조 이다. 모든 요 소 는 같은 유형의 인용 을 포함 하고 모든 다른 요 소 는 이 층 에 있다.데이터 구 조 는 당연히 그렇지 않 을 수 있다.모든 요 소 는 임의의 형식의 스칼라 를 저장 할 수 있 습 니 다. 이것 은 문자열, 숫자, 또는 모든 것 을 가리 키 는 참조 일 수 있 음 을 의미 합 니 다.이 인용 은 하나의 배열 이나 해시 참조 또는 가짜 해시 또는 이름 이나 익명 함 수 를 가리 키 는 참조 또는 대상 일 수 있 습 니 다.당신 이 할 수 없 는 유일한 일 은 하나의 스칼라 에 여러 개의 인용 물 을 채 우 는 것 입 니 다.만약 당신 이 이런 시 도 를 하고 있다 는 것 을 발견 한다 면, 그것 은 여러 개의 수 치 를 하나 로 압축 하 는 배열 이나 해시 참조 가 필요 하 다 는 것 을 나타 낸다.
다음 절 에서 코드 의 예 를 볼 수 있 습 니 다. 이 코드 들 은 기록 에 저장 하고 싶 은 많은 가능 한 유형의 데 이 터 를 보 여 주 는 것 으로 설계 되 었 습 니 다. 우 리 는 해시 참조 로 이 를 실현 할 것 입 니 다.이 키 글 자 는 모두 대문자 문자열 입 니 다. 이것 은 우리 가 자주 사용 하 는 습관 입 니 다. (가끔 은 이 습관 을 사용 하지 않 지만 우연히 사용 하지 않 습 니 다) 이 해시 가 특정한 기록 형식 으로 사용 된다 면.
 
1 더욱 유연 한 기록 의 조합, 접근 과 인쇄
다음은 여섯 가지 완전히 다른 도 메 인 을 가 진 기록 입 니 다.
 
 
   $rec = {
      TEXT       => $string,
      SEQUENCE    => [ @old_values ],
      LOOKUP    => { %some_table },
      THATCODE   => sub { $_[0] ** $_[1] },
      HANDLE   => \*STDOUT,
   };
 
 
TEXT 도 메 인 은 간단 한 문자열 입 니 다.따라서 간단하게 인쇄 할 수 있 습 니 다.
 
   print $rec->{TEXT};

 
SEQUENCE 와 LOOKUP 는 모두 일반적인 배열 과 해시 참조 입 니 다.
 
 
   print $rec->{SEQUENCE   }[0];
   $last = pop @{ $rec->{SEQUENCE} };

   print $rec->{LOOKUP}{"key"};
   ($first_k, $first_v) = each %{ $rec->{LOOKUP} };
 
 
 
THATCODE 는 명명 서브 프로 세 스 이 고 THISCODE 는 익명 서브 프로 세 스 이지 만 호출 은 같 습 니 다.
 
   $that_answer = $rec->{THATCODE}->($arg1, $arg2);
   $this_answer = $rec->{THISCODE}->($arg1, $arg2);

 
여기에 꽃 괄호 를 더 하면 $rec - > {HANDLE} 을 간접 적 인 대상 으로 볼 수 있 습 니 다.
 
   print { $rec->{HANDLE} } "a string 
";

하면, 만약, 만약... FileHandle ?  모듈, 이 핸들 을 일반적인 대상 으로 볼 수도 있 습 니 다.
 
 
   use FileHandle;
   $rec->{HANDLE}->autoflush(1);
   $rec->{HANDLE}->print("a string
");
 
 
 
 
2. 더욱 유연 한 기록 의 조합, 방문 과 인쇄
자 연 스 럽 게 당신 의 데이터 구조의 도 메 인 자체 도 임의의 복잡 한 데이터 구조 일 수 있 습 니 다.
 
 
%TV = (
    flintstones => {
        series   => "flintstones",
        nights   => [ "monday", "thursday", "friday" ],
        members  => [
            { name => "fred",    role => "husband", age  => 36, },
            { name => "wilma",   role => "wife",    age  => 31, },
            { name => "pebbles", role => "kid",     age  =>  4, },
        ],
    },


    jetsons     => {
        series   => "jetsons",
        nights   => [ "wednesday", "saturday" ],
        members  => [
            { name => "george",  role => "husband", age  => 41, },
            { name => "jane",    role => "wife",    age  => 39, },
            { name => "elroy",   role => "kid",     age  =>  9, },
        ],
    },

    simpsons    => {
        series   => "simpsons",
        nights   => [ "monday" ],
        members  => [
            { name => "homer", role => "husband", age => 34, },
            { name => "marge", role => "wife",    age => 37, },
            { name => "bart",  role => "kid",     age => 11, },
        ],
    },
);
 
 
 
3 복잡 기록 산열 의 생 성
Perl 분석 이 복잡 한 데이터 구조 가 상당히 좋 기 때문에 데이터 성명 을 Perl 코드 로 독립 된 파일 에 넣 고 도 나 require 등 내 장 된 함수 로 불 러 올 수 있 습 니 다.또 다른 유행 하 는 방법 은 CPAN 모듈 (예 를 들 어 XML: Parser) 을 사용 하여 다른 언어 (예 를 들 어 XML) 로 표 시 된 임의의 데이터 구 조 를 불 러 오 는 것 이다.
너 는 단편 적 으로 데이터 구 조 를 만 들 수 있다.
 
   $rec = {};
   $rec->{series} = "flintstones";
   $rec->{nights} = [ find_days()];

 
파일 에서 읽 어 들 이기 (여기 서 파일 의 형식 이 field = value 문법 이 라 고 가정 합 니 다):
 
 
   @members = ();
   while (<>) {
      %fields = split /[\s=]+/;
      push @members, {%fields};
   }
   $rec->{members} = [ @members ];
 
 
그 다음 에 하나의 하위 도 메 인 을 키 로 하여 더 큰 데이터 구조 에 쌓 습 니 다.
$TV{ $rec->{series} } = $rec;
데이터 복 사 를 피하 기 위해 서 추가 포인터 도 메 인 을 사용 할 수 있 습 니 다.예 를 들 어 한 사람의 기록 에 'kids' (아이) 데이터 도 메 인 을 포함 해 야 할 수도 있 습 니 다. 이 도 메 인 은 하나의 배열 일 수도 있 습 니 다. 이 배열 은 이 아이 에 게 자신 이 기록 한 인용 을 포함 하고 있 습 니 다.데이터 구조의 일부분 을 다른 부분 으로 가리 키 면 한 곳 에서 데 이 터 를 업데이트 하기 때문에 다른 곳 에서 데 이 터 를 업데이트 하지 않 아 데이터 가 기울 지 않도록 할 수 있 습 니 다.
 
 
   for $family (keys %TV) {
      my $rec = $TV{$family};      #     
      @kids = ();
      for $person ( @{$rec->{members}}) {
         if ($person->{role} =~ /kid|son|daughter/) {
            push @kids, $person;
         }
      }
      # $rec   $TV{$family}        !
      $rec->{kids} = [@kids];
   }
 
 
여기 $rec - > {kids} = [@ kids] 할당 복사 배열 내용 입 니 다. 그러나 데 이 터 를 복사 하지 않 고 간단 한 참조 일 뿐 입 니 다.이것 은 만약 당신 이 Bart 에 게 다음 과 같은 나 이 를 부여 한다 면:
$TV{simpsons}{kids}[0]{age}++; # 12 까지 증가
그러면 다음 결 과 를 볼 수 있 습 니 다. $TV {simpsons} {kids} [0] 과 $TV {simpsons} {members} [2] 는 같은 하층 익명 산 목록 을 가리 키 기 때 문 입 니 다.
print $TV{simpsons}{members}[2]{age}; # 인쇄
현재% TV 구 조 를 인쇄 합 니 다:
 
 
for $family ( keys %TV ) {
    print "the $family";
    print " is on ", join (" and ", @{ $TV{$family}{nights} }), "
"; print "its members are:
"; for $who ( @{ $TV{$family}{members} } ) { print " $who->{name} ($who->{role}), age $who->{age}
"; } print "children: "; print join (", ", map { $_->{name} } @{ $TV{$family}{kids} } ); print "

"; }
 
 
 
 데이터 구조 저장
나중에 다른 프로그램 에 사용 할 수 있 도록 데이터 구 조 를 저장 하고 싶다 면 사용 할 수 있 는 방법 이 많다.가장 쉬 운 방법 은 Perl 의 Data: Dumper 모듈 을 사용 하 는 것 입 니 다. 데이터 구 조 를 하나의 문자열 로 바 꿀 수 있 습 니 다. 이 문자열 을 프로그램 외부 에 저장 한 다음 에 eval 또는 do 로 다시 구성 할 수 있 습 니 다.
 
   use Data::Dumper;
   $Data::Dumper::Purity = 1;      #    %TV      
   open (FILE, "> tvinfo.perldata")    or die "can't open tvinfo: $!";
   print FILE Data::Dumper->Dump([\%TV], ['*TV']);
   close FILE         or die "can't close tvinfo: $!";

 
 
 
다른 프로그램 (또는 같은 프로그램) 은 나중에 파일 에서 읽 을 수 있 습 니 다.
 
 
   open (FILE, "< tvinfo.perldata")   or die "can't open tvinfo: $!";
   undef $/;            #            
   eval ;            #      %TV
   die "can't recreate tv data from tvinfo.perldata: $@" if $@;
   close FILE         or die "can't close tvinfo: $!";
   print $TV{simpsons}{members}[2]{age};

 
 
 
또는 간단 한 것 은:
 
   do "tvinfo.perldata"      or die "can't recreate tvinfo: $! $@";
   print $TV{simpsons}{members}[2]{age};

 
그리고 많은 다른 해결 방법 을 사용 할 수 있 습 니 다. 그들의 저장 형식의 범 위 는 포장 의 바 이 너 리 (매우 빠 른) 에서 XML (교환 성 이 매우 좋 음) 까지 입 니 다.다가 오 는 CPAN 미 러 를 확인 해 보 세 요!
 
 
문장의 일부 내용 은 【 전송 문 】

좋은 웹페이지 즐겨찾기