首页 > 解决方案 > Clojure 使用 into 填充贴图

问题描述

我需要填充 map {:v '[], :f '[]),其中 v-array 包含以 . 开头的行中的数据v。我怎样才能做到这一点?

文件示例:

# comment
v 1.234 3.234 4.2345234
v 2.234 4.235235 6.2345
f 1 1 1

预期结果:

{:v [(1.234 3.234 4.2345234) (2.234 4.235235 6.2345)]
 :f [(1 1 1)] }

我的尝试:

(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)))

例外:

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应该是返回结果图)

标签: parsingclojure

解决方案


我可以像这样重复您的错误消息:

(into {:v '[] :f '[]} [:v [:a :b]])

我可以做我认为程序需要的事情,如下所示:

(assoc {:v '[] :f '[]} :v [:a :b])
;; => {:v [:a :b], :f []}

在这里,我只是使用[:a :b]而不是remaining. 在您的情况下remaining是一个数字序列,但这并不重要。

至于错误消息,它是一个非常糟糕的错误消息,应该会在未来的 Clojure 版本中消失。通常是因为您map使用的是关键字而不是seq可以调用的东西。这里的信息来自某个比我能理解的更深的地方。

另一个可行的结构,我认为你想要的是:

(into {:v '[] :f '[]} [[:v [:a :b]]])

into地图需要一系列地图条目。您忘记将尝试放入地图的单个地图条目包装起来。我的 REPL 的结果:

{:v [:a :b], :f []}

推荐阅读