프로젝트 오일러 22

내 이 세상 도처에서 쉴 곳을 찾아보았으나, 마침내 찾아낸, 컴퓨터가 있는 구석방보다 나은 곳은 없더라.

프로젝트 오일러 22

영문 이름 점수 합계 구하기

문제 자세히 보기: [국어] [영어]

수학적 사고나 특별한 기교가 필요한 문제는 아니다. 그냥 문제에서 설명한 대로 처리하면 답을 얻을 수 있다. names.txt 파일을 열어보면 다음과 같이 이름이 따옴표로 묶여 있고 각 이름 사이에는 쉼표가 있다.

"MARY","PATRICIA","LINDA","BARBARA","ELIZABETH",...

먼저 파일을 읽어 불필요한 문자(따옴표, 쉼표)를 제거한 이름 목록을 만들고 이후 문제가 요구한 대로 계산하면 된다. Clojure에서는 slurp 함수를 사용하면 텍스트 파일을 쉽게 읽을 수 있다.

(ns p022
  (:require [clojure.string :as str]))

(def names
  (-> (slurp "data/names.txt") ; 파일 읽기
      (str/replace "\"" "")    ; 따옴표 제거
      (str/split #",")         ; 쉼표로 분리
      sort))                   ; 정렬

(1)파일을 읽어서 (2)따옴표를 모두 제거하고 (3)쉼표로 분리한 다음 (4)정렬하면 문제를 풀기 위한 준비가 끝난다.

각 이름의 점수를 계산하는 함수가 있으면 문제를 푸는 데 도움이 될 것이다. 점수를 계산하는 함수는 다음과 같이 작성할 수 있다.

(defn score [name]
  (apply + (map (fn [a] (- (int a) (dec (int \A)))) name)))

주어진 알파벳을 정수로 바꾸면 코드 값이 나온다. \A를 정수로 바꾸면 65가 나오는데, 각 알파벳에서 64를 빼주면 A는 1, B는 2, ... Z는 26이 된다. 이렇게 나온 숫자를 모두 더하면 점수가 된다.

이제 각 이름의 점수에 순번을 곱해야 한다. map-indexed를 사용하면 매핑할 때 순번도 알 수 있다. map-indexed의 첫 번째 인자로 전달할 함수는 인덱스와 아이템 두 개의 인자를 받는 함수여야 한다. 인덱스는 0부터 시작하므로 순번은 인덱스에 1을 더해야 한다.

(defn solve []
  (->> (map-indexed vector names)
       (map (fn [[i e]] (* (inc i) (score e))))
       (apply +)))

실행 결과는 다음과 같다.

p022> (time (solve))
"Elapsed time: 17.689125 msecs"
8711982??

참고