使用'用于'里面'让'返回哈希映射列表

时间:2014-08-02 03:05:54

标签: clojure

对不好的标题感到抱歉,因为我不知道怎么用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中的惯用方法吗?

3 个答案:

答案 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

是。

  • letmyhash绑定到{},它永远不会反弹。 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中的惯用方法吗?

没有。

@DaoWen's answer