@keedi - Seoul.pm 리더, Perl덕후, 거침없이 배우는 펄의 공동 역자, keedi.k at gmail.com
펄(Perl)에서 해시(hash)는 무척 유용한 자료구조입니다. 스크립트 언어의 가장 큰 특징이자 장점 중 하나는 배열이나 해시와 같은 복잡한 자료구조를 추가적인 라이브러리 적재없이 언어 내부에 구현해서 간단히 사용할 수 있다는 점입니다. 이러다보니 자연스럽게 계층적 자료인 경우 해시를 사용해서 저장하게 되는데 사용하다 보면 두 해시의 자료를 합쳐야 할 경우가 종종 있습니다. 단순한 해시라면 고민없이 해결하겠지만, 깊은 자료구조를 가진 해시라면 한참을 고민하거나 결국 합치는 루틴을 만들어야 하곤 합니다. 이런 류의 일은 꽤나 빈번하며, 역시 우리의 펄 선배들은 비슷한 생각을 하고 이미 바퀴를 발명해놓았지요.
필요한 모듈은 다음과 같습니다.
직접 CPAN을 이용해서 설치한다면 다음 명령을 이용해서 모듈을 설치합니다.
1 | $ sudo cpan Hash::Merge |
사용자 계정으로 모듈을 설치하는 방법을 정확하게 알고 있거나 perlbrew를 이용해서 자신만의 Perl을 사용하고 있다면 다음 명령을 이용해서 모듈을 설치합니다.
1 | $ cpan Hash::Merge |
Hash::Merge
모듈은 merge()
함수를 지원합니다.
우선 모듈 적재시 merge()
함수를 명시해서 이름공간(namespace) 지정없이 사용할 수 있도록 합니다.
물론 명시하지 않아도 Hash::Merge::merge()
처럼 이름공간을 명시해서 사용해도 됩니다.
1 | use Hash::Merge qw( merge ); |
이제 유사하지만 조금은 다른 두 해시인 %conf1
과 %conf2
를 만듭니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | my %conf1 = ( time_zone => 'Asia/Seoul' , category => { jacket => { str => '상의' , price => 10000 }, pants => { str => '바지' , price => 10000 }, shirt => { str => '와이셔츠' , price => 5000 }, shoes => { str => '구두' , price => 5000 }, tie => { str => '넥타이' , price => 2000 }, }, ); my %conf2 = ( theme => 'ace' , category => { jacket => { str => '재킷' , price => 10000 }, shirt => { str => '셔츠' , price => 5000 }, shoes => { str => '신발' , price => 5000 }, skirt => { str => '치마' , price => 10000 }, tie => { str => '넥타이' , price => 2000 }, }, ); |
합치는 법은 정말 간단합니다.
%conf1
해시와 %conf2
해시를 합쳐보죠.
1 | my %merged_conf = %{ merge( \ %conf1 , \ %conf2 ) }; |
합친 결과 해시를 풀어본 결과를 코드로 표현하면 다음과 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 | my %merged_conf1 = ( time_zone => 'Asia/Seoul' , theme => 'ace' , category => { jacket => { str => '상의' , price => 10000 }, pants => { str => '바지' , price => 10000 }, shirt => { str => '와이셔츠' , price => 5000 }, shoes => { str => '구두' , price => 5000 }, skirt => { str => '치마' , price => 10000 }, tie => { str => '넥타이' , price => 2000 }, }, ); |
잘 살펴보면 %conf2
해시에 있던 theme
키와 category.skirt
키에
해당하는 값이 추가됨을 확인할 수 있습니다.
즉 %conf1
해시의 값을 기준으로 %conf2
의 값이 추가되되,
동일한 키의 값이 있을 경우 %conf1
의 값을 유지한 것이죠.
호출할 때 %conf1
, %conf2
의 순서로 매개변수를 사용했기 때문에
Hash::Merge
는 기본적으로는 왼쪽 해시 값을 우선함을 알 수 있습니다.
오른쪽 해시 값을 우선하려면 set_behavior()
함수를 이용합니다.
1 2 | Hash::Merge::set_behavior( 'RIGHT_PRECEDENT' ); my %merged_conf = %{ merge( \ %conf1 , \ %conf2 ) }; |
'RIGHT_PRECEDENT'
를 사용하면 오른쪽 해시를 우선하며,
아무것도 지정하지 않을 경우 기본값으로 'LEFT_PRECEDENT'
값을 사용합니다.
문서에는 set_behavior()
함수 대신 set_set_behavior()
함수로
표시하기도 했는데 이는 오타이니 조심하세요.
set_behavior()
함수가 지원하는 인자 종류는 다음과 같습니다.
'LEFT_PRECEDENT'
'RIGHT_PRECEDENT'
'STORAGE_PRECEDENT'
'RETAINMENT_PRECEDENT'
좌, 우는 이미 확인했고 나머지 두 개의 경우 'STORAGE_PRECEDENT'
는 간단히 저장된 큰 값을 우선한다는 의미입니다.
즉, 스칼라보다는 배열을, 배열보다는 해시를 우선한다는 것이죠.
더불어 'RETAINMENT_PRECEDENT'
는 두 해시 값을 합칠때
기존 한 값을 버리지 않고 배열로 저장한다는 의미입니다.
조금 복잡해보이지만 꽤나 상식적으로 동작하기 때문에 몇번만 사용해보면 금방 이해할 수 있습니다. 기본 동작 자체가 합치는, 즉 머지(merge)인 관계로 동일한 키에 대해 빈 해시나 빈 배열을 정의해서 해당 키 값을 초기화할 수 없다는 점만 주의하세요.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | my %old = ( theme => 'ace' , category => { jacket => { str => '상의' , price => 10000 }, pants => { str => '바지' , price => 10000 }, }, ); my %new = ( time_zone => 'Asia/Seoul' , category => {}, ); Hash::Merge::set_behavior( 'RIGHT_PRECEDENT' ); my %result = %{ merge( \ %old , \ %new ) }; |
앞의 코드의 결과로 여러분은 category
키의 값이 빈 해시가
되길 바란다면 이것은 오해하고 있는 것입니다.
결과는 다음과 같습니다.
1 2 3 4 5 6 7 8 | my %result = ( theme => 'ace' , time_zone => 'Asia/Seoul' , category => { jacket => { str => '상의' , price => 10000 }, pants => { str => '바지' , price => 10000 }, }, ); |
category
값을 비어있게 만들고 싶다면 명시적으로 undef
를 사용해야 합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | my %old = ( theme => 'ace' , category => { jacket => { str => '상의' , price => 10000 }, pants => { str => '바지' , price => 10000 }, }, ); my %new = ( time_zone => 'Asia/Seoul' , category => undef , ); Hash::Merge::set_behavior( 'RIGHT_PRECEDENT' ); my %result = %{ merge( \ %old , \ %new ) }; |
펄(Perl) 프로그래밍 시 해시는 프로그래밍을 직관적이고 편하게 만들어주는 유용한 내장 도구입니다. 해시를 즐겨 사용하다보면 꼭 맞닥뜨리게 되는 두 해시의 내용 더하기는 비교적 간단히 보이지만, 합치는 루틴을 대충 작성할 경우, 해시의 복잡도가 커질수록 예상치 못한 버그를 맞닥뜨릴 것입니다. 두 해시를 합쳐야 할 일이 생긴다면 CPAN의 Hash::Merge 모듈을 잊지마세요.
Enjoy Your Perl! ;-)
EOT
X-mas tree
& Llama
ASCII Art by ASCII Art Farts.
Computer ASCII Art by Chris.com.
Font ASCII Art by ASCII Art Farts.
Text ASCII Art by patorjk.com.
Artwork by
Inkyung Park
& Keedi Kim.
Designed by
Hojung Youn
& Keedi Kim.
Articles by
Seoul Perl Mongers.
Edited by
Keedi Kim.
Hosting sponsored by
SILEX.
Sponsored by
SILEX.
.-''' __ __ / \/ \/ \ =-_- | \. -____- / \ // /|| '' //| //|| == = == ==