何时使用减少或替代使用pmap

时间:2012-03-22 14:28:55

标签: clojure reduce pmap

编辑:

数据真的像这样。

1,000-00-000,GRABBUS,OCTOPUS ,, M,26-Nev-12,,05 FRENCH TOAST ROAD ,, VACANT,ZA,1867,(001)111-1011,(002)111-1000 ,,

我必须让它看起来很傻,因为它包含专有信息。

这是使用clojure-csv创建矢量矢量之前的样子。

我使用解析后的数字来简化,但它们并没有减少到一个值。我想从clojure-csv解析数据中挑选某些列并创建一个较小的csv行。

请对我的道歉感到抱歉。

结束编辑:

如何确定何时使用reduce或改为使用pmap?

前一段时间,我的博客上有关于减少的评论。特别是评论说减少一般不能并行化,但map(pmap)可能是。

何时使用或不使用reduce会产生影响,例如 以下是否有所作为?

谢谢。

(def csv-row [1 2 3 4 5 6 7 8 9])
(def col-nums [0 1 4])

(defn reduce-csv-rowX
    "Accepts a csv-row and a list of columns to extract, and
     reduces the csv-row to the selected list using a list comprehension."
    [csv-row col-nums]
        (for [col-num col-nums
            :let [part-row (nth csv-row col-num nil)]]
            part-row))

(defn reduce-csv-row
    "Accepts a csv-row and a list of columns to extract, and
     reduces the csv-row to the selected list."
    [csv-row col-nums]
    (reduce
        (fn [out-csv-row col-num]
            (let [out-val (nth csv-row col-num nil)]
                (if-not (nil? out-val)
                    (conj out-csv-row out-val))))
        []
        col-nums))

编辑:

(defn reduce-csv-row     “接受csv-row和要提取的列列表,以及      将csv-row缩减为所选列表。“     [csv-row col-nums]     (降低         (fn [out-csv-row col-num]             (让[out-val(nth csv-row col-num nil)]                 (conj out-csv-row out-val)))         []         COL-NUMS))

4 个答案:

答案 0 :(得分:5)

通常,您希望使用可以编写最简单代码的函数。这通常意味着最具体的功能。在这种情况下,您可以将操作视为将列列表转换为列中行的值列表。这相当于map,因此您可能希望使用map。您可以使用reduce进行撰写,但在这种情况下,您在调用map时重新实施reduce,因此这可能是错误的方法。

但是,有时reduce是正确的选择。如果您尝试将列表“缩减”为任意值,map对您来说根本无济于事。在这种情况下,reduce就是您想要的,并且由于您的操作不可并行化,reduce也不可并行化。

如果您对reduce代码不理想的原因更感兴趣,如果我们抽象出特定于应用程序的代码,我们就会得到

(reduce
 (fn [out-list current-val]
   (let [out-val (f current-val)]
     (if-not (nil? out-val)
       (conj out-list out-val))))
 []
 col-nums)

一个复杂因素是if-not电话。目前,它的马车 - 如果out-val永远为零,你将扔掉你到目前为止所发现的所有东西并重新开始((if-not (nil? out-val) (conj out-list out-val))的回报是nil out-val 1}}为零,因此nil将用作下一个out-list)。由于你的其他实现没有任何nil检查,并且这个nil检查是错误的(因此可能从未使用过),我假设它可以被忽略。此时,您的代码是

(reduce
 (fn [out-list current-val]
   (let [out-val (f current-val)]
     (conj out-list out-val)))
 []
 col-nums)

这是map的完全有效(尽管是非懒惰)实现。使用对map的实际调用可以让您消除所有与您的特定问题实际无关的代码,而是专注于您实际尝试的操作。你可以通过查看ivant的解决方案来看到它的效果。

答案 1 :(得分:3)

使用地图的解决方案可能如下所示:

(defn reduce-csv-rowM [csv-row col-nums]
  (pmap (fn [pos] (nth csv-row pos)) col-nums))

它是平凡可并行化的,如果csv-row是一个向量,则nth非常快,所以没关系。

所以在你的情况下,我认为地图解决方案是最好的,因为它比其他两个更容易理解,并且也可以更快。

一般情况下,map和reduce不可互换,事实上它们非常有用(比如谷歌的map-reduce技术)。

答案 2 :(得分:1)

Resuce和map是一个很好的削减,它们经常被一起使用, map-reduce现在是一个常见的行业术语。通常,map用于将数据转换为可以聚合的形式,并将聚合数据减少为单个答案。如果还原功能是可交换的, reduce可以并行化。例如,使用+进行并行缩减就可以了,而使用/则效果不佳。

    如果你想制作一个集合(如列表或矢量),
  • 使用map
  • 如果您想生成单个值,请使用reduce

答案 3 :(得分:1)

您还可以使用select-keys,它以不同的格式返回响应:

(select-keys [1 2 3 4 5 6 7 8 9] [0 1 4])
;==> {4 5, 1 2, 0 1}

即从键到值的映射。它看起来更适合地图,但也适用于其他seq。

你也可以看一下clojure.set / project,它就像select-keys(实际上是在内部使用它),但对于整个表,而不是只有一行。