Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I've got a Clojure function here that's meant to parse a string of form:

"DDXXXYYY"

where DD is meant to be discarded, and XXX and YYY are string representations of integers.

(defn split-id [tileid]
  (map #(Integer/parseInt %)
       (map (partial apply str)
            (partition 3 (drop 2 tileid)))))

Or, written with the threading macro:

(defn split-id [tileid]
  (map #(Integer/parseInt %)
       (map (partial apply str)
            (->> tileid (drop 2) (partition 3)))))

Does anyone have any recommendations for a simple way to do this? It feels like clojure.contrib.string should have a partition function that takes a string and an integer.

I think I've come up with a fairly good block of code for the above function, which I had to extend a bit. I'd love comments and suggestions on the final block.

(defn parse-ints
  "Converts all strings in the supplied collection to their integer
  representation."
  [coll]
  (map #(Integer/parseInt %) coll))

(def res-map
  ^{:doc "Map between the second digit in a MODIS TileID
metadata value and the corresponding resolution."}
  {:1 "1000"
   :2 "500"
   :4 "250"})

(defn tileid->res
  "Returns a string representation of the resolution referenced by the
supplied MODIS TileID."
  [tileid]
  (res-map (keyword (subs tileid 1 2))))

(defn tileid->xy
  "Extracts integer representations of the MODIS X and Y coordinates
referenced by the supplied MODIS TileID."
  [tileid]
  (parse-ints
   (map (partial apply str)
        (partition 3 (subs tileid 2)))))

(defn split-id
  "Returns a sequence containing the resolution, X and Y
  coordinates (on the MODIS grid) referenced by the supplied MODIS
  TileID."
  [tileid]
  (flatten
   ((juxt tileid->res
          tileid->xy) tileid)))
share|improve this question

3 Answers 3

up vote 5 down vote accepted

Alternative solution is to keep it really simple:

(defn extract-int [s start end]
  (Integer/parseInt (subs s start end)))

(defn split-id [s]
  (list
    (extract-int s 2 5)
    (extract-int s 5 8)))

I believe that hardcoding two calls to extract-int is a simpler and more elegant way to meet the requirement than a solution which involves a map. Sure it's nice to use abstraction with higher-order functions, but YAGNI principle applies.

share|improve this answer

You could try the following, using the Java substring method and a vector of offsets:

(defn split-id [tileid]
  (map 
    #(Integer. (.substring tileid % (+ % 3)) ) 
    [2 5]))
share|improve this answer

Just a though, perhaps you're looking at this the wrong way. This is a parsing question, and simple parses are often best executed through regular expressions. Clojure has reader macros and special functions to work with Java regexes.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.