对不好的标题感到抱歉,因为我不知道怎么用10个字描述。这是详细信息:
我想以如下格式循环文件:
a:1 b:2 ...
我想循环每一行,将所有'k:v'收集到哈希映射中。
{a 1,b 2 ...}
我以'let'形式初始化哈希映射,然后在let表单中使用'for'循环所有行。 在每个循环步骤中,我使用'assoc'来更新原始哈希图。
(让[myhash {}]
([line#{“A:1 B:2”“C:3 D:4”}
:let [pairs (clojure.string/split line #"\s")]]
(对于[[k v](map#(clojure.string / split%1#“:”)对)]
(assoc myhash k (Float. v)))))
但最后我得到了一个懒散的hash-map,就像这样:
{{a 1,b 2 ...} {x 98 y 99 z 100 ...}}
我现在知道如何'合并'结果,但仍然不明白为什么'''内部'让'返回 结果列表。
我感到困惑的是:内部'for'中的'myhash'是否指的是每次以'let'形式声明的'myhash'?如果我确实需要像输出一样的哈希映射列表,这是Clojure中的惯用方法吗?
答案 0 :(得分:1)
Clojure" for"是list comprehension,因此它会创建列表。它不是for循环。 此外,您似乎正在尝试修改myhash,但Clojure的数据结构是不可变的。 我解决这个问题的方法是尝试创建一个对象列表([" a" 1] [" b" 2] ..)并使用(into { } the-list-of-pairs)
答案 1 :(得分:1)
如果文件格式真的像你描述的那样简单,那么更简单的东西就足够了:
(apply hash-map (re-seq #"\w+" (slurp "your-file.txt")))
如果您使用->>
threading macro:
(->> "your-file.txt" slurp (re-seq #"\w+") (apply hash-map))
slurp函数将整个文件读入字符串。 re-seq
函数只返回文件中所有单词的序列(在本例中基本上与分隔空格和冒号相同)。现在你有一系列交替的键值对,这正是hash-map
所期望的......
我知道这并没有真正回答你的问题,但你确实问过更多惯用的解决方案。
我认为@dAni是对的,你对Clojure的一些基本概念感到困惑(例如不可变的集合)。我建议您在4Clojure上完成一些练习,以此来熟悉该语言。每次解决问题时,您都可以将自己的解决方案与其他解决方案进行比较,并查看解决问题的其他(可能是更多的)解决方法。
抱歉,昨晚我发布答案时,我的代码并没有读得非常彻底。我刚刚意识到你实际上将值转换为Floats。这里有几个选项。
1)partition
输入密钥/值对的序列,以便map
覆盖它。由于您现在是一对序列,您可以使用into
将它们全部添加到地图中。
(->> "kvs.txt" slurp (re-seq #"\w") (partition 2)
(map (fn [[k v]] [k (Float. v)])) (into {}))
2)为地图声明auxiliary map-values function并在结果上使用它:
(defn map-values [m f]
(into {} (for [[k v] m] [k (f v)])))
(->> "your-file.txt" slurp (re-seq #"\w+")
(apply hash-map) (map-values #(Float. %)))
3)如果您不介意使用符号键而不是字符串,则可以安全地使用Clojure阅读器转换所有键和值。
(->> "your-file.txt" slurp (re-seq #"\w+")
(map read-string) (apply hash-map))
请注意,这是对read-string
的安全使用,因为我们对re-seq
的调用会过滤掉任何有害输入。但是,由于1
之类的数字在Clojure中是长整数,因此这将为您提供long而不是浮点数
答案 2 :(得分:0)
内部myhash
中的for
是否每次引用myhash
表单中声明的let
?
是。
let
将myhash
绑定到{}
,它永远不会反弹。 myhash
始终为{}
。 assoc
返回修改后的地图,但不会改变myhash
。所以代码可以简化为
(for [line ["A:1 B:2" "C:3 D:4"]
:let [pairs (clojure.string/split line #"\s")]]
(for [[k v] (map #(clojure.string/split %1 #":") pairs)]
(assoc {} k (Float. v))))
...产生相同的结果:
(({"A" 1.0} {"B" 2.0}) ({"C" 3.0} {"D" 4.0}))
如果我想要一个像输出一样的哈希映射列表,这是Clojure中的惯用方法吗?
没有。