Clojure中的映射

时间:2015-07-29 20:21:34

标签: dictionary clojure

如何让这段代码正常工作?它应输出四个索引号,然后从地图中随机选择名称。

(def persons {0 "name1" 1 "name2" 2 "name3"})
(map #(println (str %1 ": " %2)) (iterate inc 0) (persons (rand-int 3)))

请不要以其他方式提出建议,但如果您知道应如何纠正,请更正我的代码。 它应输出如下内容: 0:name2,1:name3,2:name1

5 个答案:

答案 0 :(得分:4)

代码(persons (rand-int 3))中的问题会从地图中生成一个随机值,例如" name3"和地图将其视为一系列字符(\n \a \m \e \3)

只需将其包裹几次即可:

(repeatedly 4 #(persons (rand-int 3)))

正确且更清洁的方式:

(dotimes [i 4]
  (println (str i ":" (rand-nth (vals persons)))))
  • 如果您想要副作用(打印)
  • ,请使用dotimes代替map
  • 使用(rand-nth (vals persons))代替(persons (rand-int 3)),如果您的地图增长并变为100个元素,rand-nth仍然表现得像预期,而rand-int则基于地图尺寸

答案 1 :(得分:3)

这里有几点需要注意:

  1. 如果要迭代一系列事物并执行一些包含副作用的操作(如打印),则应使用doseq而不是map。

  2. 如果你正在处理地图,你给mapdoseq的函数应该有一个参数,一个MapEntry - 有点像一个2项列表包含密钥和值。您可以使用解构来获取密钥和值。

  3. 你可以这样做:

    (def persons {0 "name1" 1 "name2" 2 "name3"})
    
    (doseq [[i name] persons]
      (println (str i ": " name)))
    

    这并没有捕捉到你想要做的事情的随机性方面,但为此我遵从@ mishadoff的回答。

答案 2 :(得分:3)

我强烈建议“保持简单”如下:

(def persons {0 "name1" 1 "name2" 2 "name3"})
(let [names       (vals persons)
      names-shuf  (shuffle names)
      idx         (range (count names)) ]
  (doseq [ii idx]
    (println (str ii ": " (nth names-shuf ii)))))

产生:

~/clj > lein run
0: name2
1: name1
2: name3

或类似(每次都不同)。请注意,我们在此处使用shuffle来确保地图中每个名称的确切结果为1。

答案 3 :(得分:2)

目前您的代码存在一些问题。首先,map使用带副作用的方法(如编写输出)不是一个好主意。映射是一种懒惰的操作,所以当你认为它必然会发生。相反,你应该构建一个你想要的字符串列表,然后打印出来。

其次,map期望其参数(映射函数除外)是可迭代的数据集合。但(persons (rand-int 3))会从persons中选择一个项目。这仍然有效,因为persons中的值是字符串,但它没有做你想要的。我会改变你的代码(试图让它接近你原来的代码):

(def persons {0 "name1" 1 "name2" 2 "name3"}) ; Same data as before
(def output ; Making strings, instead of trying to print them inside the map
     (map #(str % ": " (persons (rand-int 3))) ; Select one name for each number
          (range 3))) ; Only take 3 items, so we don't have an infinite list
(println output) ; Actually display the result

答案 4 :(得分:2)

map接受一个函数和一个或多个集合。你给了它两个集合:一个惰性序列((iterate inc 0))和一个字符串((persons (rand-int 3)))。因此,不是以随机顺序打印名称,而是按随机选择的字符串的顺序打印字符。

我认为你希望给它一组随机名称。想想你想要的是这个:

(def persons {0 "name1" 1 "name2" 2 "name3"})
(def randomnames 
  (letfn [(makenames [] 
            (lazy-seq (cons (persons (rand-int 3)) 
                            (makenames))))]
    (makenames)))
(map #(println (str %1 ": " %2)) (take 3 (iterate inc 0)) (take 3 randomnames))

以上解决方案使用替换打印随机名称​​;没有替换它的做法会更复杂,但你明白了。这个缺陷是你使用一个随机的人作为map的第二个参数,当你真的想要一个随机人的集合时,比如说一个向量,他们都乱了。