2015년 9월 13일 일요일

Code Golf - 4Clojure 92번 문제

4Clojure 92번 문제는 Read Roman numerals.

로마표기수를 읽어들이는 함수를 작성하는 문제다.

(= 3999 (__ "MMMCMXCIX"))

빼기 표현에 주의해야 한다!

M = 1000
M = 1000
M = 1000
CM = 900  (C = -100, M = 1000)
XC = 90     (X = -10, C = 100)
IX = 9        (I = -1, X = 10)

(= 48 (__ "XLVIII"))

XL = 40  (X = -10, L = 50)
V = 5 
I = 1
I = 1
I = 1 

WWDC 2013년 공식 로고가 떠오른다. 
-- developer.apple.com에서
MMXIII = 2013
MM = 2000
X = 10
III = 3

일단 단순한 풀이는 빼기 규칙이 적용되느냐 아니냐를 결정하고 그런 다음 모두 더하는 것.

;; 130
(fn [roman]
  (let [m {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1}
        p (map (fn[a b]
                 (if (< (m a) (m b))
                   (- (m a))
                   (m a)))
               roman
               (rest roman))]
    (apply + (m (last roman)) p)))

이제 골프 시작~

zipmap은 keys와 vals로 map을 만드는 쉬운 방법이다. 그러나 이 경우는 코드가 더 길어진다.

기본적인 인라인으로 줄여보면,

;; 105
(fn [m r]
  (apply + 
         (m (last r))
         (map (fn [a b]
                (if (< (m a) (m b))
                  (- (m a))
                  (m a)))
              r
              (rest r)))) {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1}

m을 항상 적용하고 있으니 미리 적용시키면 될 것 같다.

;; 102
(comp
 (fn [r]
  (apply + 
         (last r)
         (map (fn [a b]
                (if (< a b)
                  (- a)
                  a))
              r
              (rest r)))) 
 #(map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1} %))

comp 이득이 없는 것 같아 다시 let 을 써 봤는데, 마찬가지. ㅠ.ㅠ

;; 103
(fn [x]
  (let [r (map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1} x)]
  (apply + 
         (last r)
         (map (fn [a b]
                (if (< a b)
                  (- a)
                  a))
              r
              (rest r))))) 

일단 #() 을 써서 줄이기

;; 100
(fn [x]
  (let [r (map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1} x)]
  (apply + 
         (last r)
         (map #(if (< %1 %2) (- %1) %1)
              r
              (rest r))))) 

%1 중복 제거하여 1을 줄일 수 있었다.

;; 99
(fn [x]
  (let [r (map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1} x)]
  (apply + 
         (last r)
         (map #((if (< %1 %2) - +) %1)
              r
              (rest r))))) 

#()의 중복을 피해서 더 줄일 수 있다.

;; 96
#(let [r (map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1} %2)]
  (apply + 
         (last r)
         (map %1
              r
              (rest r)))) #((if (< %1 %2) - +) %1)

comp를 써도 같은 길이를 구할 수 있다.

;; 96
(comp
 #(apply + 
         (last %)
         (map (fn [a b] (if (< a b) (- a) a))
              %
              (rest %)))
 #(map {\M 1000 \D 500 \C 100 \L 50 \X 10 \V 5 \I 1} %))


댓글 없음:

댓글 쓰기