Когда использовать уменьшить или вместо использования pmap - PullRequest
1 голос
/ 22 марта 2012

Редактировать:

Данные действительно выглядят так.

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 меньшего размера.

Пожалуйста, примите мои извинения за любую путаницу.

Конец редактирования:

Как вы определяете, когда следует использовать сокращение или вместо этого использовать pmap?

Некоторое время назад я получил комментарий в своем блоге по поводу снижения.В частности, в комментарии говорится, что сокращение в общем случае не может быть распараллелено, но карта (pmap) может быть такой.

Когда использование или не использование уменьшения будет иметь значение, и для примеров, подобных приведенному ниже, это имеет значение?

Спасибо.

(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 redu-csv-row "Принимает csv-строку и список столбцов для извлечения, а также уменьшаетcsv-row в выбранный список. "[csv-row col-nums] (уменьшите (fn [out-csv-row col-num] (let [out-val (n-й csv-row col-num nil)] (конout-csv-row out-val))) [] col-nums))

Ответы [ 4 ]

5 голосов
/ 22 марта 2012

В общем, вы хотите использовать функцию, которая позволяет вам писать простейший код. Обычно это означает наиболее конкретную возможную функцию. В этом случае вы можете рассматривать свою операцию как преобразование списка столбцов в список значений строки в столбце. Это соответствует 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 равен нулю, поэтому 1023 * будет использоваться как следующий out-list). Так как ваша другая реализация не имеет никакой проверки на ноль, и эта проверка на ноль содержит ошибки (и поэтому, вероятно, никогда не использовалась), я предполагаю, что ее можно игнорировать. На данный момент ваш код

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

, которая является абсолютно допустимой (хотя и не ленивой) реализацией map. Использование фактического вызова map позволяет вместо этого исключить весь этот код, который на самом деле не связан с вашей конкретной проблемой, и вместо этого сосредоточиться на том, что вы на самом деле пытаетесь сделать. Вы можете увидеть эффект от этого, посмотрев на решение Иванта.

3 голосов
/ 22 марта 2012

Решение с использованием карты может выглядеть так:

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

Это тривиально распараллеливаемо, и если csv-row является вектором, nth довольно быстрый, так что все в порядке.

Так что в вашем случае я считаю, что картографическое решение является лучшим, потому что его легче понять, чем два других, а также может быть быстрее.

В общем случае карта и уменьшение не являются взаимозаменяемыми и фактически весьма полезны вместе (как в методах сокращения карт Google).

1 голос
/ 23 марта 2012

Вы также можете использовать клавиши выбора, которые возвращают ответ в несколько ином формате:

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

То есть отображение ключа на значение.Он выглядит лучше для карт, но работает и для других последовательностей.

Вы также можете взглянуть на clojure.set / project, который похож на клавиши выбора (и фактически использует его внутри), но дляцелая таблица вместо одной строки.

1 голос
/ 23 марта 2012

Resuce и map - отличная пара, и они используются вместе так часто, что map-Reduction теперь является общепринятым в отрасли термином .в общем карта используется для преобразования данных в форму, которая может быть агрегирована и сводить агрегированные данные в один ответ. уменьшить можно распараллелить, если функция уменьшения коммутативна .например, параллельное сокращение подходит для + и работает менее эффективно для /.

  • , используйте map, если вы хотите создать коллекцию (например, список иливектор)
  • используйте reduce, если хотите, чтобы производил одно значение , например, 42
...