수정일: 2023년 08월 08일
4clojure - Prime Numbers (67)
문제
(= (__ 2) [2 3])
(= (__ 5) [2 3 5 7 11])
(= (last (__ 100)) 541)
풀이
(fn [n]
(take n (filter
(fn [x] (= (count (filter #(= (mod x %) 0)
(conj (range 1 (inc (int (Math/sqrt x)))) x)))
2))
(range 2 600))))
풀이과정
우선 소수를 구할 수에 대한 리스트가 필요하다. 수에 대한 리스트를 만들기 위해서 range를 사용 했다 단, 소수는 2부터 시작을 해야하므로 아래와 같다
(range 2 10)
;; (2 3 4 5 6 7 8 9)
세번째 문제가 500번이 넘어가므로 안전하게 600번까지 리스트를 만들었다.
소수를 구하기 위해서는 자신을 제외한 약수가 1밖에 없어야 한다. 하지만 현재 주어진 숫자로 무식하게 자기 자신까지 나눈다는 것은 좀 아니라는 생각이 들어 제곱근을 구해서 최대한 검증의 갯수를 줄여주는 리스트를 만드는 것이 필요하다.
(range 1 (inc (int (Math/sqrt 9))))
;; (1 2 3)
9에 대한 제곱근이 1, 2, 3어야 하므로 range의 마지막 수는 포함되지 않아 inc로 증가를 해서 포함되게 하였다.
자기 자신의 값도 포함되어야 하므로 아래와 같이 포함을 했다.
(conj (range 1 (inc (int (Math/sqrt 9)))) 9)
;; (9 1 2 3)
위 리스트에서 9로 나누어 0이 되는 값의 리스트를 구한다.
(filter #(= (mod 9 %) 0) (conj (range 1 (inc (int (Math/sqrt 9)))) 9))
;; (9 1 3)
위 식은 1개의 값인 9에 대한 약수의 리스트만 구했다. 9는 약수의 갯수가 위와 같이 3개 이므로 소수가 아니다.
우리는 2부터 600번까지의 소수를 구해야 하므로 다시 filter로 약수의 갯수가 2가 되는 값만 찾아주면 된다.
예시로는 10까지의 약수를 찾아주는 문제로 바꿨다.
(filter (fn [x] (= (count (filter #(= (mod x %) 0) (conj (range 1 (inc (int (Math/sqrt x)))) x))) 2)) (range 2 10))
;; (2 3 5 7)
문제에서 주는 파라미터가 n번째까지의 소수를 구하는 문제이므로 take로 갯수를 가져온다.
(take n (filter (fn [x] (= (count (filter #(= (mod x %) 0) (conj (range 1 (inc (int (Math/sqrt x)))) x))) 2)) (range 2 10)))
이것을 테스트에 맞게 fn으로 감싸주면 문제는 해결된다.
(fn [n]
(take n (filter
(fn [x] (= (count (filter #(= (mod x %) 0)
(conj (range 1 (inc (int (Math/sqrt x)))) x)))
2))
(range 2 600))))
해답을 본 것 중에서 some, remove로 구한 해답도 있었다. some은 주어진 조건이 참인 경우에 or 형태로 true로 계산하는 함수이고, remove는 조건이 true이면 제거를 하는 함수이다. 내가 본 답에서는 1개라도 나눴을 때 0이 된다면 리스트 목록에서 제거를 하는 방식을 택했다.
그것을 약간 내가 만든 식으로 변형을 한 해답이다
(remove (fn [x] (some #(zero? (rem x %)) (range 2 (inc (int (Math/sqrt x)))))) (range 2 10))
;; (2 3 5 7)