tags:

views:

176

answers:

6

I have the following input:

(def nums [123456789012 123456789012])

I'd like the following output:

[[1234 5678 9012] [1234 5678 9012]]

*note both of these sequence contain numbers not strings...

I figured this would be really simple by doing the following:

  1. Convert each entry into a String
  2. Partition each string by 4
  3. Convert each partition back into an integer

Here is my failed attempt:

(defn split-nums [nums factor]
  (map
    #(map
       (fn [x] (Integer/valueOf (str x)))
       (partition factor (str %)))
  nums))

(println (split-nums nums, 4))

When I run this I get the following error:

Caused by: java.lang.NumberFormatException: For input string: "clojure.lang.LazySeq@4834333c"

Which tells me I am dealing with a lazy sequence that I need to force evaluation on but when I try to (str (doall x)) I get the same result.

So clojure experts where am I going wrong? Is this a good approach? BTW. I've just started to learn clojure so I'm certainly not an expert.

+2  A: 

To fix yours:

(defn split-nums [nums factor]
  (map #(map (fn [x] (Integer/valueOf (apply str x))) ;; apply str
             (partition factor (str %)))
       nums))

(str (lazy-seq [1])) ;; => "clojure.lang.LazySeq@20"

(apply str (lazy-seq [1])) ;; => "1"

I'd probably write it to accept one number, then use map, instead of taking a coll.

(defn split-number [n factor]
  (->> (str n)
       (partition-all factor) ;; or partition
       (map (partial apply str))
       (map #(Integer/valueOf %))))

(map #(split-number % 4) [12345678 12345678]) ;; => ((1234 5678) (1234 5678))

If you'd rather work with integers, rather than strings:

(mod 5151 10) ;; => 1 Gets the least significant digit.

(/ 5151 10) ;; => 515 Removes the least significant digit.

MayDaniel
Thank you for pointing out exactly where I went wrong - stringing together the sequence rather than stringing together each element in the sequence yielding a new string. Also, I agree with your idea of making the method accept a single number. I'm still used to other languages that have less powerful/concise ways of handling collections.Finally, yeah probably better to just deal directly with the number rather than doing conversions.
Travis
+1  A: 
(def nums [123456789012 123456789012])

(defn part-int [l n] 
  (map #(Integer. (apply str %)) 
    (partition l (str n))))

(map (partial part-int 4) nums)
;; => ((1234 5678 9012) (1234 5678 9012))
Michiel Borkent
thanks works great!
Travis
+3  A: 

In this case I think for is really good to use. You don't have that many map.

(def nums [123456789012 123456789012])

(for [num nums] 
    (map #(Integer. (apply str %)) 
          (partition 4 (str num))))
;; => ((1234 5678 9012) (1234 5678 9012))
nickik
You have an extra closing paran - easy to do. otherwise works fine.
Travis
Is correct now.
nickik
+1  A: 

Slight variation of solution above by @nickik

(partition 3
  (map #(Integer. (apply str %))
       (partition 4 
         (apply concat (map str nums)))))
peacefulfire
(apply concat (map ...)) = (mapcat ...)
MayDaniel
Your solution is actually a little more flexible since you are doing two partitions so you could easily make the code produce [[1234 5678] [9012 1234] [5678 9012]] which wasn't one of my requirements but is still interesting.
Travis
+3  A: 

Why convert to String first? Here is a version with / and mod. This will also fix your leading zeros problem.

(defn int-partition [num size]
   (let [f (int (Math/pow 10 size))]
      (loop [n num l ()]
         (if (zero? n) 
            (vec l) 
            (recur (int (/ n f)) (conj l (mod n f)))))))

(defn split-nums [nums factor] (vec (map #(int-partition % factor) nums)))
Kintaro
+1  A: 
user=> (map #(->> % (str) (partition 4) (map (fn [s] (read-string (apply str s))))) nums)
((1234 5678 9012) (1234 5678 9012))

It's better to extract functions.

edbond
read-string is more than ten times slower than using Integer. or Integer/parseInt or Integer/valueOf etc.
MayDaniel
Works but does have issues with leading zeros. If the input was [123406789012 123406789012] it would fail. Thanks for the alternate solution though.
Travis