Clojure将函数列表应用于参数列表

Clojure将函数列表应用于参数列表,clojure,Clojure,我有一个调整价格的功能列表和一个产品列表。 作为一种产出,我希望有相同的产品清单,但价格有所调整 从技术上讲,有一个功能列表和一个地图列表。 我试图实现的是将每个函数顺序地应用于列表中的每个映射,同时保留初始结构 (def products [{:id 1 :price 100} {:id 2 :price 200}]) (defn change-price "increase by 10 => (change-price product 10 +)" [product

我有一个调整价格的功能列表和一个产品列表。 作为一种产出,我希望有相同的产品清单,但价格有所调整

从技术上讲,有一个功能列表和一个地图列表。 我试图实现的是将每个函数顺序地应用于列表中的每个映射,同时保留初始结构

(def products
  [{:id 1 :price 100}
   {:id 2 :price 200}])

(defn change-price
  "increase by 10 => (change-price product 10 +)"
  [product amount price-func]
  (update product :price #(int (price-func amount %))))

(defn adjust-price
  [products]
  ;;fn-list is a list of price adjuster functions
  (let [fn-list [#(change-price % 10 +)
                 #(change-price % 50 -)]]
  ;; so I map a function to each product
  ;; which applies all adjsuter functions to that product
    (merge (map (fn [prod] 
        (map #(% prod) fn-list)) products)))
似乎我不明白如何正确地减少结果,因为我得到的是一个嵌套列表,如

   (change-price products)
=> (({:id 1, :price 110} {:id 1, :price -50})
    ({:id 2, :price 210} {:id 2, :price -150}))
但我想

({:id 1, :price 60} {:id 2, :price 160})

提前谢谢。

问题是
map
不会“挤压”结果:它只会生成list[n]=>list[n]

您需要的是
reduce
,如下所示:

user> (let [fn-list [#(change-price % 10 +)
                     #(change-price % 50 -)]]
        (map (fn [p] (reduce #(%2 %1) p fn-list))
             products))

;;=> ({:id 1, :price -60} {:id 2, :price -160})

此外,您还必须重写
更改价格
函数,因为这里的参数数错误:
(价格函数金额%)
=>
(价格函数金额%)

问题是
映射
不会“挤压”结果:它只是生成列表[n]=>list[n]

您需要的是
reduce
,如下所示:

user> (let [fn-list [#(change-price % 10 +)
                     #(change-price % 50 -)]]
        (map (fn [p] (reduce #(%2 %1) p fn-list))
             products))

;;=> ({:id 1, :price -60} {:id 2, :price -160})

此外,您还必须重写
更改价格
函数,因为此处的参数数目错误:
(价格函数金额%)
=>
(价格函数百分比金额)

似乎您要应用函数的组合:

(defn adjust-price
  [products]
  (let [fn-list [#(change-price % 10 +)
                 #(change-price % 50 -)]
        f (apply comp fn-list)]
    (map f products)))

似乎您希望应用函数的组合:

(defn adjust-price
  [products]
  (let [fn-list [#(change-price % 10 +)
                 #(change-price % 50 -)]
        f (apply comp fn-list)]
    (map f products)))

您没有对传入的hashmap进行变异,因此当您以这种方式对一个项调用两个不同的函数时,将得到不同的结果

在“调整价格”函数中,由于您使用“映射”来执行“更改价格”函数,因此您当前的意思是,运行第一个更改价格函数一次,返回一个值,然后运行第二个价格函数一次,返回一个单独的值,结果是: ({:ID1,:price 110}{:ID1,:price-50})

上面的答案很好,只是我想我应该添加另一种方法来使用线程函数来实现它,这样您就不必担心顺序了

(defn adjust-price
  [products]
  (let [f #(-> % 
               (change-price 10 +)
               (change-price 50 -))]
    (map f products)))
请记住,单线程'->'表示将当前行(函数)的结果向下传递到下一行(函数),并将其用作第一个参数


(顺便说一句,我知道这是一篇老文章,但希望这能在将来帮助其他人:)

你没有改变传入的hashmap,所以当你以这种方式对一个项目调用两个不同的函数时,你会得到不同的结果

在“调整价格”函数中,由于您使用“映射”来执行“更改价格”函数,因此您当前的意思是,运行第一个更改价格函数一次,返回一个值,然后运行第二个价格函数一次,返回一个单独的值,结果是: ({:ID1,:price 110}{:ID1,:price-50})

上面的答案很好,只是我想我应该添加另一种方法来使用线程函数来实现它,这样您就不必担心顺序了

(defn adjust-price
  [products]
  (let [f #(-> % 
               (change-price 10 +)
               (change-price 50 -))]
    (map f products)))
请记住,单线程'->'表示将当前行(函数)的结果向下传递到下一行(函数),并将其用作第一个参数


(注:我知道这是一个老帖子,但希望这能在将来帮助别人:)

谢谢;这也是一个完全有效的解决方案。请注意,虽然此解决方案在这种特定情况下工作正常,但它将从右向左应用函数(这是正常的,因为x+10-50==x-10+50),可能会在顺序重要的情况下导致一些混乱。在这种情况下,您可能需要
(应用comp(反向fn列表))
谢谢;这也是一个完全有效的解决方案。请注意,虽然此解决方案在这种特定情况下工作正常,但它将从右向左应用函数(这是正常的,因为x+10-50==x-10+50),可能会在顺序重要的情况下导致一些混乱。在这种情况下,您可能需要
(应用comp(反向fn列表))