이번에도 모두 2일차 진행하며 풀어봤던 문제들이다. 한번에 쭈욱~ 달릴 수 있는 것을 길게 늘여놓았구나 싶다.
문제 30, 이어진 중복 제거.
(= (apply str (__ "Leeeeeerrroyyy")) "Leroy")
loop/recur로 풀수 있는 문제지만 accumulator의 last를 비교해야 한다는 점이 조금 거슬린다. 이건 아마도 Haskell느낌? 하지만 Clojure의 vector는 last도 효율적이니까!
(fn [list]
(loop [list list
acc []]
(if (empty? list)
acc
(if (= (last acc) (first list))
(recur (rest list) acc)
(recur (rest list) (conj acc (first list)))))))
이미 있는 sequence함수를 사용한다면 reduce로 쉽게 구현된다.
reduce (fn[a b](if (= (last a) b) a (conj a b))) []
그런데 만약 map/filter 등의 sequence함수들처럼 lazy sequence를 반환해야 한다면 어떻게 할 수 있을까? 단순히loop/recur + accumulator로는 안될 것이다.
Rx의 distinctUntilChanged와 같다! 직접 마지막 요소를 keep해도 되지만 drop-while을 이용하면 편리하다. 그리고 오히려 더 간단하다!
(fn duc[coll]
(lazy-seq
(when-let [s (seq coll)]
(let [f (first s)]
(cons f (duc (drop-while #(= % f) (rest s))))))))
laziness를 확인하려면 함수에 (range) 와 같은 무한시퀀스를 적용시키고 앞에서 (take 5)처럼 가져오면 된다. 첫번째 코드는 undefined이며 두번째는 잘 동작한다.
31번, 이어진 같은 값 묶기.
(= (__ [1 1 2 1 1 1 3 3]) '((1 1) (2) (1 1 1) (3 3)))
아무 생각없이 loop/recur로 작성하면 된다. 이 문제는 내가 가끔 연습문제로 소개하는 개미수열의 하위 문제이기도 하다. (take-while/drop-while)을 이용하면 간단하다. 물론 자주 등장하기 때문에 (split-with)가 이미 있다!
이문제도 lazy sequence를 반환하도록 하려면 lazy-seq을 이용해야 한다.
(fn pack[coll]
(lazy-seq
(when-let [s (seq coll)]
(let [f (first s)
[hd tl] (split-with #(= % f) s)]
(cons hd (pack tl))))))
그런데 Code Golf를 보니 엄청 짧은 답들이 많다. 어떻게 한 것일까?
laziness 제거하고 77
(fn p[c]
(when-let[s (seq c)]
(let [f (first s)
[t d](split-with #(= % f) s)]
(cons t (p d)))))
50글자 이내의 답들이 있는 걸보면 vector를 가정한 것이 아닐까 싶다.
67글자
(fn p[c](if(seq c)(let[[t d] (split-with #(= % (c 0)) c)](cons t(p (vec d))))))
에구, 더는 안되겠다!
41번, n번째마다 버리기.
(= (__ [1 2 3 4 5 6 7 8] 3) [1 2 4 5 7 8])
이건 오히려 loop/recur가 더 어렵겠다. 이미 있는 partition(-all)을 이용하면 간단하다.
(fn[c n](apply concat (partition-all (dec n) n c)))
45번, iterate.
(= __ (take 5 (iterate #(+ 3 %) 1)))
간단하니 넘어가고..
33번, replicate.
(= (__ [1 2 3] 2) '(1 1 2 2 3 3))
두번씩 반복한 32번 문제의 일반화!
(fn[c n](mapcat #(repeat n %) c))
이렇게 1주일이 지났다. 함수형 프로그래밍 언어들의 연습문제들이 서로 비슷하다. 비슷한 문제들이기 때문에 언어적인 부분을 비교해보기 좋다.
문제 30, 이어진 중복 제거.
(= (apply str (__ "Leeeeeerrroyyy")) "Leroy")
loop/recur로 풀수 있는 문제지만 accumulator의 last를 비교해야 한다는 점이 조금 거슬린다. 이건 아마도 Haskell느낌? 하지만 Clojure의 vector는 last도 효율적이니까!
(fn [list]
(loop [list list
acc []]
(if (empty? list)
acc
(if (= (last acc) (first list))
(recur (rest list) acc)
(recur (rest list) (conj acc (first list)))))))
이미 있는 sequence함수를 사용한다면 reduce로 쉽게 구현된다.
reduce (fn[a b](if (= (last a) b) a (conj a b))) []
그런데 만약 map/filter 등의 sequence함수들처럼 lazy sequence를 반환해야 한다면 어떻게 할 수 있을까? 단순히loop/recur + accumulator로는 안될 것이다.
Rx의 distinctUntilChanged와 같다! 직접 마지막 요소를 keep해도 되지만 drop-while을 이용하면 편리하다. 그리고 오히려 더 간단하다!
(fn duc[coll]
(lazy-seq
(when-let [s (seq coll)]
(let [f (first s)]
(cons f (duc (drop-while #(= % f) (rest s))))))))
laziness를 확인하려면 함수에 (range) 와 같은 무한시퀀스를 적용시키고 앞에서 (take 5)처럼 가져오면 된다. 첫번째 코드는 undefined이며 두번째는 잘 동작한다.
31번, 이어진 같은 값 묶기.
(= (__ [1 1 2 1 1 1 3 3]) '((1 1) (2) (1 1 1) (3 3)))
아무 생각없이 loop/recur로 작성하면 된다. 이 문제는 내가 가끔 연습문제로 소개하는 개미수열의 하위 문제이기도 하다. (take-while/drop-while)을 이용하면 간단하다. 물론 자주 등장하기 때문에 (split-with)가 이미 있다!
이문제도 lazy sequence를 반환하도록 하려면 lazy-seq을 이용해야 한다.
(fn pack[coll]
(lazy-seq
(when-let [s (seq coll)]
(let [f (first s)
[hd tl] (split-with #(= % f) s)]
(cons hd (pack tl))))))
그런데 Code Golf를 보니 엄청 짧은 답들이 많다. 어떻게 한 것일까?
laziness 제거하고 77
(fn p[c]
(when-let[s (seq c)]
(let [f (first s)
[t d](split-with #(= % f) s)]
(cons t (p d)))))
50글자 이내의 답들이 있는 걸보면 vector를 가정한 것이 아닐까 싶다.
67글자
(fn p[c](if(seq c)(let[[t d] (split-with #(= % (c 0)) c)](cons t(p (vec d))))))
에구, 더는 안되겠다!
41번, n번째마다 버리기.
(= (__ [1 2 3 4 5 6 7 8] 3) [1 2 4 5 7 8])
이건 오히려 loop/recur가 더 어렵겠다. 이미 있는 partition(-all)을 이용하면 간단하다.
(fn[c n](apply concat (partition-all (dec n) n c)))
45번, iterate.
(= __ (take 5 (iterate #(+ 3 %) 1)))
간단하니 넘어가고..
33번, replicate.
(= (__ [1 2 3] 2) '(1 1 2 2 3 3))
두번씩 반복한 32번 문제의 일반화!
(fn[c n](mapcat #(repeat n %) c))
이렇게 1주일이 지났다. 함수형 프로그래밍 언어들의 연습문제들이 서로 비슷하다. 비슷한 문제들이기 때문에 언어적인 부분을 비교해보기 좋다.
댓글 없음:
댓글 쓰기