如何将函数应用于Clojure中的范围?

时间:2015-02-28 10:01:18

标签: clojure

我是Clojure的新手,我尝试使用clojuredocs.org中的示例数据。

;; Data
(def scenes [{:subject "Frankie"
              :action "say"
              :object "relax"}

         {:subject "Lucy"
          :action "loves"
          :object "Clojure"}

         {:subject "Rich"
          :action "tries"
          :object "a new conditioner"}])

(defn play [scenes n]
  "Play a scene"
  (->>
   scenes
   (#(get % n))
   ((juxt :subject :action :object))
   (interpose " ")
   (apply str)))

play功能正常工作:

my-stuff.core> (play scenes 0)
"Frankie say relax"
my-stuff.core> (play scenes 1)
"Lucy loves Clojure"
my-stuff.core> (play scenes 2)
"Rich tries a new conditioner"

play-all功能无效:

(defn play-all [scenes]
  "Play all the scenes"
  (let [x (count scenes)]
    (for [n (range x)]
      (map play scenes n ))))

如何更正此play-all功能,即如何将播放功能应用于数据范围?

3 个答案:

答案 0 :(得分:2)

您不需要for map

仅限for

user=> (defn play-all [scenes]
  #_=>   "Play all the scenes"
  #_=>   (let [x (count scenes)]
  #_=>     (for [n (range x)]
  #_=>       (play scenes n ))))
#'user/play-all
user=> (play-all scenes)
("Frankie say relax" "Lucy loves Clojure" "Rich tries a new conditioner")

且只有map

user=> (defn play-all [scenes]
  #_=>   "Play all the scenes"
  #_=>   (let [x (count scenes)]
  #_=>     (map #(play scenes %1) (range x))))
#'user/play-all
user=> (play-all scenes)
("Frankie say relax" "Lucy loves Clojure" "Rich tries a new conditioner")

(我更喜欢后者。)

编辑:如果您喜欢->>,那就更好了:

user=> (defn play-all [scenes]
  #_=>   "Play all the scenes"
  #_=>   (->> scenes
  #_=>     (count)
  #_=>     (range)
  #_=>     (map #(play scenes %))))
#'user/play-all
user=> (play-all scenes)
("Frankie say relax" "Lucy loves Clojure" "Rich tries a new conditioner")

答案 1 :(得分:0)

map遍历集合(或多个集合)以生成序列。 forlist comprehension构建序列。 在您的情况下,您可以使用其中一个

就分解而言,实际上有一个能够播放一个场景的功能会让人感觉很明显:

(defn play-one [scene]
  "Play a scene"
  (->>
   scene
   ((juxt :subject :action :object))
   (interpose " ")
   (apply str)))

然后播放第n个可以使用先例定义:

(defn play-nth [scenes n]
  "Play the n(th) scene"
  (->
   scenes
   (#(get % n))
   play-one))

你有几种方法可以播放所有场景:

(defn play-all-map1 [scenes]
  "Play all the scenes"
 (map (partial play-nth scenes) (range (count scenes))))

但是你可以真正简化,因为你不需要range因为scenes可以被视为一个序列(假设你对索引不感兴趣):

(defn play-all-map2 [scenes]
  "Play all the scenes with map"
  (map play-one scenes))

使用for

(defn play-all-for [scenes]
  "Play all the scenes with for"
  (for [scene scenes]
    (play-one scene)))

答案 2 :(得分:0)

在我们对它做任何事情之前,你的play函数应该处理一个场景:

(defn play [scene]
  "Play a scene"
  (->> scene
   ((juxt :subject :action :object))
   (interpose " ")
   (apply str)))

你这样使用它:

(play (scenes 0))
;"Frankie say relax"

......这比以前更容易或更难。但

  • 它适用于任何场景和
  • 场景不必保存在矢量中。

它还使play-all更简单:

(defn play-all [ss]
  (map play ss))

(play-all scenes)
;("Frankie say relax" "Lucy loves Clojure" "Rich tries a new conditioner")

我很想用((juxt :subject :action :object))中的vals替换play,但我们不能依赖地图条目的顺序。