루비가 쿨한 이유 3 - 해시

Posted by 大山 Sun, 06 Aug 2006 17:51:00 GMT

[참고: 이 글은 루비가 쿨한 이유 1 - irb, 루비가 쿨한 이유 2 - 블록에 이어지는 시리즈임.]

해시(Hash)는 Associative Array라고도 종종 불리는데 루비에서 가장 많이 쓰이는 데이타 구조 중 하나이다. 해시에는 키값과 데이타가 짝으로 저장되는데, 다음과 같은 식이다.

h = Hash.new
h["name"] = "홍길동"
h["age"] = 18
h["sex"] = "남자"
 

저장한 데이타를 불러오려면 원래의 키값만 알고 있으면 된다. 예를 들어, h["name"]은 "홍길동"을 리턴한다. h["address"]와 같이, 존재하지 않는 키값이 입력되면 nil이 리턴된다.

해시는 대부분의 프로그래밍 언어에서 지원되지만, 모든 프로그래밍 언어에서 같은 빈도로 활용되지는 않는다. 보통 Perl이나 루비 코드에는 해시가 넘쳐나는데 반해, 자바 코드에서는 해시를 찾아보기가 어렵다.

이런 현상은 프로그래밍 언어는 평등하지 않다는 것을 보여주는 또다른 예라고 할 수 있다. 자바의 해시는 HashMap 클래스의 API를 통해서만 사용이 가능하지만, 루비나 Perl은 언어의 신택스 레벨에서 해시를 지원하기 때문이다.

예를 들어, 자바에서 숫자와 요일을 매핑하는 해시를 만드려면 다음과 같은 코드가 필요하다.

import java.util.HashMap;

class HashExample {
  static void main(String[] argv) {
    HashMap h = new HashMap();
    h.add(new Integer(0), "일요일");
    h.add(new Integer(1), "월요일");
    h.add(new Integer(2), "화요일");
    h.add(new Integer(3), "수요일");
    h.add(new Integer(4), "목요일");
    h.add(new Integer(5), "금요일");
    h.add(new Integer(6), "토요일");
  }
}
 

루비에서는 다음과 같다.

h = {0 => "일요일", 1 => "월요일", 2 => "화요일",
     3 => "수요일", 4 => "목요일", 5 => "금요일",
     6 => "토요일"}
 

왜 자바 개발자들이 해시를 잘 안쓰는지는 읽는 분의 상상에 맡긴다. 해시가 유용한 경우는 정말로 많은데, 대표적인 예는 특정 이벤트가 일어난 횟수를 저장하기 위해서이다. 예를 들어, 웹 로그 파일에서 특정 IP 주소의 접속 빈도를 합산하는데 사용할 수 있다.

c:\> irb --simple-prompt
>> f = File.open("access_log", "r")
>> h = Hash.new(0)
>> f.each {|line| h[$1] += 1 if line =~ /^(\d+\.\d+\.\d+\.\d+)/}
 

위에서 Hash.new(0)이라고 한 것은, 해시에 아직 저장되지 않은 키값을 입력했을때 nil 대신에 0을 리턴하도록 해준다.

해시의 키값이나 데이타에는 어떤 객체도 들어갈 수 있기 때문에 또다른 해시 객체가 데이타로 들어갈 수도 있다. 예를 들어 다음과 같은 식이다.

h = {1 => {"name" => "이승만", "from" => 1948, "to" => 1960},
     2 => {"name" => "윤보선", "from" => 1960, "to" => 1962},
     3 => {"name" => "박정희", "from" => 1963, "to" => 1979},
     4 => {"name" => "최규하", "from" => 1979, "to" => 1980},
     5 => {"name" => "전두환", "from" => 1980, "to" => 1988},
     6 => {"name" => "노태우", "from" => 1988, "to" => 1993},
     7 => {"name" => "김영삼", "from" => 1993, "to" => 1998},
     8 => {"name" => "김대중", "from" => 1998, "to" => 2003},
     9 => {"name" => "노무현", "from" => 2003, "to" => 2008}}
 

대통령들의 재임 기간을 계산해 보는 것도 간단하다.

(1..9).each do |i|
  puts h[i]["name"] + ": " +
       (h[i]["to"] - h[i]["from"]).to_s + "년"
end

이승만: 12년
윤보선: 2년
박정희: 16년
최규하: 1년
전두환: 8년
노태우: 5년
김영삼: 5년
김대중: 5년
노무현: 5년
 

루비 설치는 이곳을 참고!

Posted in  | Tags ,  | 6 comments | no trackbacks

Comments

  1. 1.
    kebie said about 7 hours later:

    루비가 쿨한 이유 3번은 PHP도 부분적으로 해당되는 사항이군요. 파일을 객체로 받아서 바로 each 를 쓰는거나 따로 함수등을 통하지 않고 정규식을 바로쓸 수 있는 부분은 정말 편리해 보이네요. :)


  2. 2.
    大山 said about 13 hours later:

    @kebie: 루비는 기존의 언어를 여럿 참고해서 만들어 졌습니다. 정규식과 해시는 Perl, 객체지향과 블록은 SmallTalk, 메타프로그래밍은 Lisp에서 차용한 식이죠.

    기존 언어의 이상적인 개념(텍스트처리, 객체지향, 메타프로그래밍)을 몽땅 따다가 만들었기 때문에, 루비를 포스트모던 언어라고도 부릅니다. 결과적으로 루비는 상당히 편리하면서도 무척이나 강력한 언어가 되었지요~ :)


  3. 3.
    홍민희 said about 21 hours later:

    Ruby도 어서 Python처럼 와이드 문자(wide character)를 지원했으면 좋겠습니다.


  4. 4.
    大山 said about 21 hours later:

    @홍민희: 사실 루비는 지금도 utf-8 인코딩을 비롯해서 와이드 문자 처리를 제법 지원하고 있습니다. 구체적으로 어떤 문제를 가지고 계신지요?


  5. 5.
    홍민희 said 10 days later:

    String이 “바이트열”이 아닌 진정한 “문자열”이어야 한다고 생각합니다. 아직은 '한글'.length는 2가 아니죠. Python에서 len(u'한글')은 2입니다. Ruby에서는 유니코드 객체 같은 것이 없는 것 같더군요.


  6. 6.
    大山 said 11 days later:

    접근방법의 차이라고도 생각되는데요, 유니코드 지원과 m17n 지원을 별도로 보는 시각도 존재합니다. 루비 진영에서는 유니코드가 m17n의 궁극적 해결책이라는 주장에 대해 다소 비판적인 시각이 존재하고, Matz도 문자열마다 인코딩이 별도로 지정되어야 한다는 입장을 보이고 있지요.

    m17n에 대한 완벽한 지원은 루비 2.0에서 계획되어 있기는 합니다만, 현재도 utf-8 인코딩 정도는 지원하고 있습니다.

    루비 프로그램에 다음 두 라인이 들어가면, 문자열 길이와 같은 기본적인 기능이 지원됩니다.

    $KCODE = "u"
    require 'jcode'
    

    이제 '한글'.jlength를 입력하면, 2가 리턴되지요. 보다 고차원적인 유니코드 지원을 원하시면, unicode gem과 unicode_hacks를 설치하시면 됩니다.


Trackbacks

Use the following link to trackback from your own site:
http://beyond.daesan.com/articles/trackback/823

Comments are disabled