DATA 전문가로 가는 길

[Perl] Hash(해쉬)란? 본문

Programming/Perl

[Perl] Hash(해쉬)란?

EstenPark 2009. 3. 27. 23:52

스칼라 변수와 배열 그외에 어떤 변수가 있는지 아실 겁니다.
사실 저도 이번에 해쉬 문법을 배우면서 참 유용하게 쓰일 곳이 많을 거라고 생각 했습니다.

해쉬는 key + value값을 가지고 일종의 배열 역활을 합니다.
문자열을 첨자로서 값을 취득할 수 있는 배열이라고 생각해도 나쁘지 않다고 생각 합니다.

%(백분율 기호)를 사용 하여 배열을 선언 합니다.
 my %hash = ( 'key' =>'values' );
  • 변수의 접두사는 %
  • (key1 => value1, key2 => value2 .... )
  • 부모(key)와 자식(value)으로 비유하기도 합니다.
  • 해쉬의 키값으로는 문자열이나 변수명이 올 수 있는데, 굳이 이중인용부호로 감싸지 않아도 됩니다. 그러나, 만일 키값이 2byte문자체계인 한글이 사용된다면 반드시 인용부호가 필요하다는 점 기억해야 합니다.
print "$hash{key} \n";

결과 : values

  • 출력하는 경우, %가 아니라 $기호로 단일 요소를 취급해야 합니다.
  • {}를 사용하여 키를 지정합니다. (배열은 []을 기준으로 하겠죠?) 

이 정도면 해쉬를 어떻게 사용하는지 어떻게 출력 하는지 알 수 있을 거라고 생각 합니다. 그리고 중요한 건 연관 배열 관련 함수인데요. 이것은 해쉬로 들어있는 값을 print문으로 계속 하는 것은 맞지 않다고 생각 합니다. 연관 배열 내에서 다음 키/값을 쌍으로 두 개의 요소를 갖고 오는 방법도 있으니 방법은 다양 합니다.


 keys(%ARRAY)  %ARRAY내의 모든 "key"의 목록을 리턴 (목록은 랜덤하며, 순서는 내부적으로 사용된 해쉬함수에 의존
 values(%ARRAY)  %ARRAY내의 모든 "valus'의 목록을 리턴
 each(%ARRAY)  %ARRAY로 함수가 호출 될 때마다 연관 배열 내의 다음 "key/value"를 쌍으로 구성하여 두개의 요소를 갖는 목록을 리턴
 delete($ARRAY{KEY})  %ARRAY로 부터 KEY와 연관된 "key/value"을 제거

 
1. keys 함수

use strict;
use warnings;

my %math_score = (
        'eng'  => 58,
        'mat'  => 100,
        'perl' => 120,
);

my $sum;
my $cnt;

foreach
my $key ( sort keys %math_score ) {
        print "$key : $math_score{$key} \n";
        $sum += $math_score{$key};
        $cnt++;

}
print"-----------------------\n";
print"         RESULT        \n";
print"-----------------------\n"
;

printf "SUM : %4d AVG : %0.2f \n",$sum, $sum / $cnt
;

print"-----------------------\n"
;

결과 :

eng : 58
mat : 100
perl : 120
-----------------------
         RESULT       
-----------------------
SUM :  278 AVG : 92.67
-----------------------




설명

  • keys 함수를 이용하여 해쉬의 각각의 요소들을 foreach에 건내 줍니다.
  • print "$key : $math_score{$key} \n"; 이부분에서 위에서 설명했던 key를 이용하여 value를 출력
    printf "SUM : %4d AVG : %0.2f \n",$sum, $sum / $cnt; 따로 설명이 .....
  • 제가 프로그램을 만들면서 혼란 스러웠던건 스칼라변수를 어디에 써야하고 각 lexical scope(영역)을 구분하기가 어려웠습니다. 가장 간단한 방법은 { }를 기준으로 생각하시면 될 것 같습니다.


2. each 함수

use strict;
use warnings;

my %math_score = (
        'eng'  => 58,
        'mat'  => 100,
        'perl' => 120,
);


my $sum;
my $cnt;
while ( (my $key, my $value) = each(%math_score) ) {
        print "$key = $value \n";
        $sum += $value;
        $cnt++;
}



print"-----------------------\n";
print"         RESULT        \n";
print"-----------------------\n";

printf "SUM : %4d AVG : %0.2f \n", $sum, $sum / $cnt;

print"-----------------------\n";

결과 :
perl = 120 
mat = 100 
eng = 58 
-----------------------
         RESULT        
-----------------------
SUM :  278 AVG : 92.67 
-----------------------

  • (my $key, my $value) = each(%math_score)
    each 함수는 해쉬를 인수하여 키와 값을 스칼라 변수로 전달합니다.
  • each 함수는 순서부를 정의 할 수 없으며, 사전 순서를 변경 하기 위해서는 keys함수를 사용
  • each 함수는 메모리 소비량은 많지 않지만 keys 함수는 키의 모든 것을 메모리에 활당


3. delete 함수

 #!/usr/bin/perl

use strict;
use warnings;

my %math_score = (
        'eng'  => 58,
        'mat'  => 100,
        'perl' => 120,
);


my $sum;
my $cnt;
my $key;
my $value;

delete($math_score{perl});

while ( ($key, $value) = each(%math_score) ) {
        print "$key = $value \n";
        $sum += $value;
        $cnt++;
}



print"-----------------------\n";
print"         RESULT        \n";
print"-----------------------\n";

printf "SUM : %4d AVG : %0.2f \n", $sum, $sum / $cnt;

print"-----------------------\n";

결과 :

mat = 100 
eng = 58 
-----------------------
         RESULT        
-----------------------
SUM :  158 AVG : 79.00 
-----------------------

  • delete($math_score{perl}); 해쉬에 등록된 값을 삭제 하는 방법이며, "perl"이라는 key를 제거하게 되면 key/value 모두 제거 하게 됩니다. 그래서 실제로 결과를 보면 perl이라는 해쉬는 존재 하지 않습니다.


그외에 reverse 함수도 있습니다. 방법은 key/value를 서로 값을 바꿔 주는 함수라고 생각 하시면 됩니다.
예 : my %y  = reverse %x  ;

전체적인 해쉬를 설명할 수는 없습니다. 해쉬를 이용하여 래퍼런스 혹은 디래퍼런스를 활용 할 수도 있고
배열에 해쉬를 작성하여 래퍼런스 임시적 래퍼런스 값을 추려낼 수도 있습니다.

4. 응용 사례

 

#!/usr/bin/perl use strict; use warnings; my @server_data = ( { id=>'estenpark', pass=>'ucess', ip=>'203.223.233.231' }, { id=>'m12' , pass=>'ucess', ip=>'203.223.233.232' }, { id=>'mas12' , pass=>'ucess', ip=>'203.223.233.233' }, { id=>'ma2345' , pass=>'ucess', ip=>'203.223.233.234' } ); my $server_data; foreach my $ip ( @server_data ) { printf "ID : %10s PW : %10s IP : %16s \n", $ip->{id}, $ip->{pass}, $ip->{ip}; }

결과 : 
ID :   estenpark  PW :      ucess  IP :  203.223.233.231 
ID :       m12  PW :      ucess  IP :  203.223.233.232 
ID :      mas12  PW :      ucess  IP :  203.223.233.233 
ID :     ma2345  PW :      ucess  IP :  203.223.233.234 

위와 같은 방법은 배열에 해쉬를 이용하여 필요한 정보를 수집하는 자료구조입니다.
{ id=>'estenpark', pass=>'ucess', ip=>'203.223.233.231' },
..
..
배열에 원소는 4개가 되지만, 실제적으로 값을 해쉬 배열이 됩니다. 그것은 실제 주소를 불러오면 알 수 있습니다.
foreach my $ip ( @server_data ) {  출력 } 위에서 말한 것 처럼 배열에 있는 원소를 변수에 전달 하게 되면 그 값을 역 참조하여 값을 추려 낼 수 있습니다.
printf "ID : %10s  PW : %10s  IP : %16s \n", $ip->{id}, $ip->{pass}, $ip->{ip};
$ip ->{id} 각각의 원소 안에 해쉬의 key를 넣어 주면 value를 출력 하게 됩니다.



5. 적용 방법
 
#!/usr/bin/perl

use strict;
use warnings;

my %server_data = (
        '203.223.233.231'=> { id=>'estenpark', pass=>'ucess', },
        '203.223.233.232'=> { id=>'mass'    , pass=>'ucess', },
        '203.223.233.233'=> { id=>'mas12'   , pass=>'ucess', },
        '203.223.233.234'=> { id=>'ma2345'  , pass=>'ucess', }
);

foreach my $ip ( keys %server_data ) {
        printf "ID : %10s  PW : %10s  IP : %16s \n", $server_data{$ip}->{id}, $server_data{$ip}->{pass}, $ip;
}
결과 :
ID :   estenpark  PW :      ucess  IP :  203.223.233.231 
ID :      mas12  PW :      ucess  IP :  203.223.233.233 
ID :     ma2345  PW :      ucess  IP :  203.223.233.234 
ID :       mass  PW :      ucess  IP :  203.223.233.232 


저도 해쉬 변수에 넣은 방법을 보고 어떻게 하면 출력 할까.. 정말 많은 고민을 했습니다. 만약 '203.223.233.231' 번의 아이피의 id를 알고 싶다면 어떻게 해야 할까요?? print "$server_data2{'203.223.233.231'}->{id} \n";

현재 소스에는 4개의 배열 밖에 없지만 실제로 서버가 100대 2000대 라면 그걸 모두 print문으로  하면 코딩도 길어지고 정말 쓸모 없는 작업을 하게 됩니다.
foreach my $ip ( keys %server_data ) { 출력 } 앞서 말한 것 처럼 해쉬 변수에 적용 되어있기 때문에 keys 함수를 이용해서 각 원소의 결과를 가지고 올 수 있었습니다.

정렬을 하고 싶다면 sort 를 적용 시켜서 사용 하셔도 됩니다.
foreach my $ip ( sort keys %server_data ) { 출력 } 이렇게 하면 정렬 되겠죠?


참고 자료
================================================================================
             사이트                                                      이름

================================================================================
http://aero.springnote.com/                                                       (aero님)
http://h0ney.pe.kr/                                                                   (hOney님)
http://doc.perl.kr/twiki/bin/view/Wiki/HowToStartPerl                  (펄덕펄덕)
http://cafe.naver.com/perlstudy.cafe                                 (대한민국Perl커뮤니티)
================================================================================








 




Comments