4cloujure – clojure的趣味试题集

对于lisp我只有一点点的scheme功底,但是scheme要做一些现实世界的编程还是有点难的.clojure是common lisp在jvm上的方言,在jvm上意味着它可以使用现实世界大量的java实现,可以快速的解决实际问题。
4clojure.com就是用clojure来实现的一个趣味教学网站,它提供大量的clojure趣味试题让你在解题中掌握clojure。这几天我就沉迷于其中不可自拔,随便拿一题难道我的题目给大家分享。

题目是这样的A Nil Key

A nil key:
Write a function which, given a key and map, returns true iff the 
map contains an entry with that key and its value is nil.
test not run	
(true?  (__ :a {:a nil :b 2}))
test not run	
(false? (__ :b {:a nil :b 2}))
test not run	
(false? (__ :c {:a nil :b 2}))

要我们写一个函数,给定一个key和map判断key是不是在map中,不在就返回false,在map中就判断这个key所对应的value是不是nil是就返回true不是就返回false。
这个题的难度是Elementary,可是它还真的花了我不少时间,由于对Clojure不是很熟悉我只能找了个reference对照着按我的想法来试。最后写了一个相当命令式风格的答案

#(if (first
   (for [x (keys %2)
         :when (= x %1)]
     (nil?  (%1 %2)))) true false)

用for来遍历map,在map中找到相对应的key时就判断key对应的value是否为空,不为空就返回nil,为空就返回(true)记得因为for返回的结果是列表所以是(true)而不是true,因此我们就要用first从列表中把true取出来。最后再来判断结果,是true就返回true是nil就返回false。好吧,我承认是个超级垃圾的写法。

来欣赏几个好的写法

(fn [k m] (and (nil? (k m)) (contains? m k)))

我怎么就没找到contains?这个东东呢?

#(nil? (get %2 %1 1))

原来get后面还可以跟一个not found参数啊,看来我读手册不够认真。

再来看一题Map Defaults

When retrieving values from a map, you can specify default 
values in case the key is not found:
(= 2 (:foo {:bar 0, :baz 1} 2))
However, what if you want the map itself to contain the default values?
Write a function which takes a default value and a sequence of
keys and constructs a map.
(= (__ 0 [:a :b :c]) {:a 0 :b 0 :c 0})
(= (__ "x" [1 2 3]) {1 "x" 2 "x" 3 "x"})
(= (__ [:a :b] [:foo :bar]) {:foo [:a :b] :bar [:a :b]})

题目就是给你一个value,和一个key的列表, 要你生成一个map,里面的key来自key列表,value是给定的value
先来看我的SB做法:

(fn [%1 %2]
   (let [list ((fn [%1 %2]
                (for [key %2]
                  (array-map key %1))
                ) %1 %2)]
     (conj (last list) (first (rest list)) (first list))))

我用了lambda的嵌套,先用for生成一个({key val}{key val}{key val})的列表,在对这个列表里的元素做conj将列表里的三个map合成一个map,相当弱智及投机取巧的做法吧,哈。
看看别人怎么做的,用assoc和reduce

(fn [x s] (reduce #(assoc %1 %2 x) {} s))

巧妙吧,还有用into和zipmap的,没什么技巧

#(into {} (map (fn [k] [k %]) %2))

zipmap的:

#(zipmap %2 (repeat %1))

用apply的也挺简洁的

#(apply hash-map (interleave %2 (repeat %1)))

用loop递归的,也挺麻烦的

#(loop [n (count %2) ret {} fs (first %2) rs (rest %2)]
  (if (zero? n)
    ret
    (recur (dec n) (merge ret {fs %1}) (first rs) (rest rs))
    )
  )

虽然我的比较投机取巧,但是在只知道for和一些基本的操作下把它做出来了,我还是很有成就感滴。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.