Reputation: 839
Say I have a file with lines that look like this apple,pie,100,1000
. From each line I would like to have a vector like this ["apple" "pie" 100 1000]
, where the first two are strings and the second to are integers or Longs or whatever.
A solution could be
(defn foo [line]
(let [[a b c d] (split line #",")]
[a b (Integer/parseInt c) (Integer/parseInt d)]))
which does what I want, but I'm not sure if there may be a better (or more idiomatic) way to do this or not.
From this question What's the easiest way to parse numbers in clojure? , I found out about clojure.edn, so I could use read-line
like this
(map read-string (clojure.string/split "apple,pie,12,134" #","))
;=> (:apple :pie 12 134)
but that gives me symbols instead of strings.
This question Convert a sequence of strings to integers (Clojure) is also similar, except that the lines contain only numbers and not numbers and strings.
Note: clojure-csv (https://github.com/davidsantiago/clojure-csv) and clojure.data.csv (https://github.com/clojure/data.csv) don't appear to have a function that automatically does this.
Upvotes: 2
Views: 657
Reputation: 84369
You could use data.csv to parse your data and Prismatic's schema to coerce field values to the desired types:
;; [org.clojure/data.csv "0.1.2"]
;; [prismatic/schema "0.2.2"]
(require '[schema.core :as s]
'[schema.coerce :as coerce]
'[clojure.data.csv :as csv])
(def field-schemas [s/Str s/Str s/Int s/Int])
(def field-coercers
(mapv coerce/coercer
field-schemas
(repeat coerce/string-coercion-matcher)))
(defn coerce-fields [fields]
(mapv #(%1 %2) field-coercers fields))
And finally:
(map coerce-fields (csv/read-csv "apple,pie,12,134"))
;= (["apple" "pie" 12 134])
Upvotes: 3
Reputation: 13483
Not very elegant, but
(map numberise (clojure.string/split "apple,pie,12,134" #","))
; ("apple" "pie" 12 134)
where
(defn numberise [s]
(try (Integer/parseInt s)
(catch NumberFormatException nfe s)))
Upvotes: 0
Reputation: 2539
I think there is a library out there that makes this very easy. Can't remember the name of it but it worked like so
(let [structure [str str int int]]
(map #(% %2)
structure
(map read-string (clojure.string/split "apple,pie,12,134" #",")))
;=> ("apple" "pie" 12 134)
Upvotes: 0