HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

More succinct / ideal solution to Project Euler #22

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
idealmoreprojecteulersuccinctsolution

Problem

"Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.

For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 × 53 = 49714.

What is the total of all the name scores in the file?"

I'm relatively new to clojure, and this is what I came up with:

(def names (sort (map (fn[x] (replace x #"\"" "")) (split (slurp "/users/calvinfroedge/Downloads/names.txt") #","))))

(loop [i 0 total 0]
  (if (not= i (count names))
    (recur (inc i) (+ total (* (inc i) (reduce + (map (fn[x] (- (int x) 64)) (nth names i))))))
    total)


I read somewhere that doseq is preferred to loop/recur, but it wasn't apparent to me how to comprehensibly AND idiomatically approach this problem without using an explicit loop with an incrementing value.

Am I missing something?

Solution

Yes. I think you still miss a very useful part of clojure - using its various collection types to model your solution. In your problem, you could use the fact that a string is a seq and a map acts as a function to calculate the cost of a word:

;; this map will act as a function from a name to its ordinal
(def name->position (zipmap names (map inc (range))))

;; and this map will act as a function from letter to its ordinal
(def ab-map (zipmap alphabet (map inc (range))))


Now that we have these two functions, we could easily calculate a name's value in this way:

(defn score [word]
  (* (reduce + (map ab-map word))
     (name->position word 0)))


You can now calculate COLIN:
(score "COLIN")

Explicit recursion can many times be avoided by using functions like map and reduce, mainly because often the sequences themselves are defined in terms of recursion

From here, you could solve this question by using map and reduce with the new function score

Code Snippets

;; this map will act as a function from a name to its ordinal
(def name->position (zipmap names (map inc (range))))

;; and this map will act as a function from letter to its ordinal
(def ab-map (zipmap alphabet (map inc (range))))
(defn score [word]
  (* (reduce + (map ab-map word))
     (name->position word 0)))

Context

StackExchange Code Review Q#48553, answer score: 7

Revisions (0)

No revisions yet.