如何在Clojure中使用reduce实现map

mlu*_*own 9 clojure map-function

在本节末尾的"勇敢与真实的Clojure"中,减少了一个挑战:

如果你想要一个真正让你的头发恢复的运动,请尝试map使用reduce

事实证明,这比我想象的要困难得多(至少对我来说是一个Clojure初学者).经过几个小时,我想出了这个:

(defn map-as-reduce
  [f coll]
  (reduce #(cons (f %2) %1) '() (reverse coll)))
Run Code Online (Sandbox Code Playgroud)

这是一个更好的方法吗?我特别感到沮丧的是,我必须反转输入集合才能使其正常工作.它似乎有点不雅!

Sam*_*tep 10

请记住,您可以在向量的末尾有效插入:

(defn map' [f coll]
  (reduce #(conj %1 (f %2)) [] coll))
Run Code Online (Sandbox Code Playgroud)

例:

(map' inc [1 2 3])
;=> [2 3 4]
Run Code Online (Sandbox Code Playgroud)

map'与原作之间的一个区别map是原文map返回的是一个ISeq而不是一个Seqable:

(seq? (map inc [1 2 3]))
;=> true

(seq? (map' inc [1 2 3]))
;=> false
Run Code Online (Sandbox Code Playgroud)

您可以通过组合上述实施解决这个问题map'seq:

(defn map' [f coll]
  (seq (reduce #(conj %1 (f %2)) [] coll)))
Run Code Online (Sandbox Code Playgroud)

现在最重要的区别是,虽然原始map是懒惰的,但这map'是渴望的,因为reduce是渴望.


lee*_*ski 9

只是为了好玩:map真的接受多个集合作为参数.这是一个扩展实现:

(defn map-with-reduce
  ([f coll] (seq (reduce #(conj %1 (f %2)) [] coll)))
  ([f coll & colls]
    (let [colls (cons coll colls)]
      (map-with-reduce (partial apply f)
                       (partition (count colls) 
                                  (apply interleave colls))))))
Run Code Online (Sandbox Code Playgroud)

在repl中:

user> (map-with-reduce inc [1 2 3])
(2 3 4)

user> (map-with-reduce + [1 2 3] [4 5] [6 7 8])
(11 14)
Run Code Online (Sandbox Code Playgroud)


小智 7

真实的地图在其集合参数上调用seq并返回一个懒惰的seq,所以也许这可以使它更接近真实的地图?

(defn my-map
  [f coll]
  (lazy-seq (reduce #(conj %1 (f %2)) [] (seq coll))))
Run Code Online (Sandbox Code Playgroud)

我会补充说,作为评论,但我没有声誉.:)