I need to fill map {:v '[], :f '[])
, where v-array contains data from line that starts with v
. How can I do this?
Example of file:
# comment
v 1.234 3.234 4.2345234
v 2.234 4.235235 6.2345
f 1 1 1
Expected result:
{:v [(1.234 3.234 4.2345234) (2.234 4.235235 6.2345)]
:f [(1 1 1)] }
My try:
(defn- file-lines
[filename]
(line-seq (io/reader filename)))
(defn- lines-with-data
[filename]
(->>
(file-lines filename)
(filter not-empty)
(filter #(not (str/starts-with? % "#")))))
(defn- create-model
[lines]
(doseq [data lines]
(into {:v '[] :f '[]}
(->>
(let [[type & remaining] data]
(case type
"v" [:v remaining]
"f" [:f remaining]))))))
(defn parse
[filename]
(->>
(lines-with-data filename)
(map #(str/split % #"\s+"))
(create-model)))
Exception:
user=> (p/parse "test.obj")
IllegalArgumentException Don't know how to create ISeq from: clojure.lang.Keyword clojure.lang.RT.seqFrom (RT.java:542)
(parse
should be return result map)
I can repeat your error message like this:
(into {:v '[] :f '[]} [:v [:a :b]])
I can do what I think the program requires like this:
(assoc {:v '[] :f '[]} :v [:a :b])
;; => {:v [:a :b], :f []}
Here I just used [:a :b]
instead of remaining
. In your case remaining
is a sequence of numbers, but it doesn't really matter.
As for the error message it is quite a bad one, that should be gone in coming versions of Clojure. Usually it is because you are presenting map
with a keyword rather than something that seq
can be called on. Here the message is coming from somewhere a bit deeper than I can comprehend.
Another construction that would work, and is I think what you wanted, is:
(into {:v '[] :f '[]} [[:v [:a :b]]])
into
a map requires a sequence of map-entry. You forgot to wrap the single map-entry you were trying to place into the map. Result from my REPL:
{:v [:a :b], :f []}