1

编辑:

数据真的是这样的。

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?

不久前,我在博客上收到了关于 reduce 的评论。具体来说,评论说 reduce 通常不能并行化,但 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 行和要提取的列列表,并将 csv 行减少到所选列表。" [csv-row col-nums] (reduce (fn [out-csv- row col-num] (let [out-val (nth csv-row col-num nil)] (conj out-csv-row out-val))) [] col-nums))

4

4 回答 4

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为零,因此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 的解决方案,您可以看到它的效果。

于 2012-03-22T17:17:15.603 回答
3

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

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

它很容易并行化,如果 csv-row 是一个向量 nth 非常快,所以没问题。

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

在一般情况下,map 和 reduce 是不可互换的,事实上它们一起非常有用(就像在 google 的 map-reduce 技术中一样)。

于 2012-03-22T15:28:04.100 回答
1

Resuce 和 map 是一个很好的搭配,它们经常一起使用,以至于map-reduce 现在是一个常见的行业术语。一般来说,map 用于将数据转换为可聚合的形式,reduce 将数据聚合为单个答案。如果 reduce 函数是可交换的,则 reduce 可以并行化。例如,并行归约+适用于/.

  • map如果您想生成一个集合(如列表或向量),请使用
  • reduce如果你想产生像 42 这样的单个值,请使用
于 2012-03-22T22:04:05.053 回答
1

您还可以使用选择键,它以稍微不同的格式返回响应:

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

也就是说,从键到值的映射。它在地图上看起来更好,但也适用于其他序列。

您还可以查看 clojure.set/project,它类似于 select-keys(实际上在内部使用它),但用于整个表,而不仅仅是一行。

于 2012-03-23T08:05:48.093 回答