Search code examples
listdictionaryclojure

Clojure. Storing two Integers and a Double from User Input into a List


I am trying to store two integers and a double from User Input into a list in Clojure. Any and all help is greatly appreciated!

My standard input to the console: 12 1 5.30.

Here is my code:

(ns clojure.partial.map
(:gen-class))

(defn string-to-list [s]
  (re-seq #"\d+\d+(\d+)?\.(\d+)?" s))

(defn convert-seq-of-int-to-strings [ss]
  (let [new_partition (partition-all 2 ss)
       map-one (map #(Integer/parseInt %) (take 1 new_partition))
       map-two (map #(Double/parseDouble %) (take 1 (drop 1 new_partition)))
       map-concat (concat (map-one map-two))]
   (doseq [item map-concat]
   (println item)))

(def user-input (read-line))

(def new-sequence (string-to-list new-line))

(def converting-seq-to-list (convert-seq-of-int-to-strings new-seq))

; Expected Output: 
; 12
; 1
; 5.30

Error Message:

Execution error (ClassCastException) at clojure.partial.map/convert-seq-of-int-to-strings.
class clojure.lang.LazySeq cannot be cast to class clojure.lang.IFn

(clojure.lang.LazySeq and clojure.lang.IFn are in unnamed module of loader 'app')

Solution

  • There is actually much more errors than one let, but let's start from that:

    • You're missing parentheses around let and missing brackets around bindings in this let.
    • (concat (map-one map-two)) is causing this exception: class clojure.lang.LazySeq cannot be cast to class clojure.lang.IFn. map-one isn't function, so you should call this concat like this: (concat map-one map-two)
    • Regex in string-to-list can't parse your string "5 10 2.84". You could rewrite that into something like this:
    (->> (re-seq #"\d+(\.\d+)?" "5 10 2.84")
         (map first))
    => ("5" "10" "2.84")
    

    Or even more readable clojure.string/split:

    (clojure.string/split "5 10 2.84" #" ")
    => ["5" "10" "2.84"]
    
    • I don't understand why you need to use partition, so I will skip this one.
    • Replace Integer/parseInt and Double/parseDouble with parse-long and parse-double. You will actually need only one, because parse-double also handles strings without a decimal dot. Or you can use clojure.edn/read-string, if you want to get numbers of desired types.
    • Your function convert-seq-of-int-to-strings actually returns nil, as result of doseq. And its name is misleading, you're converting a sequence of strings into a sequence of numbers.

    With all these changes, your code could look like this:

    (defn input-to-seq []
      (let [numbers (->> (clojure.string/split (read-line) #" ")
                         (mapv clojure.edn/read-string))]
        (doseq [item numbers]
          (println item))
        numbers))