Когда использовать уменьшить или вместо использования pmap

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

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

1,000-00-000, GRABBUS, OCTOPUS,, M, 26-Nev-12, 05 Французская тостовая дорога,,VACANT,ZA,1867,(001) 111-1011,(002) 111-1000,,

Я должен заставить это выглядеть глупо, потому что он содержит конфиденциальную информацию.

Вот как это выглядит перед использованием clojure-csv для создания вектора векторов.

Я использовал числа после разбора, чтобы упростить его, но они не уменьшаются до значения. Я хочу выбрать некоторые столбцы из проанализированных данных clojure-csv и создать меньшую строку csv.

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

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

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

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

4 ответа

Решение

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

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

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

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

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

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

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

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

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

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

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

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