Вот две аналогичные функции, как имя столбца, так и сохранение порядка.
(defn transform-column [col-name f data]
(let [new-col-names (sort-by #(= % col-name) (col-names data))
new-dataset (conj-cols
(sel data :except-cols col-name)
(f ($ col-name data)))]
($ (col-names data) (col-names new-dataset new-col-names) )))
(defn transform-rows [col-name f data]
(let [new-col-names (sort-by #(= % col-name) (col-names data))
new-dataset (conj-cols
(sel data :except-cols col-name)
($map f col-name data))]
А вот пример, иллюстрирующий разницу:
=> (def test-data (to-dataset [{:a 1 :b 2} {:a 3 :b 4}]))
=> (transform-column :a (fn [x] (map #(* % 2) x)) test-data)
[:a :b]
[2 2]
[6 4]
=> (transform-rows :a #(* % 2) test-data)
[:a :b]
[2 2]
[6 4]
transform-rows
лучше всего подходит для простыхпреобразования, где transform-column
для случая, когда преобразование для одной строки зависит от других строк (например, при нормализации столбца).
Сохранение и загрузка CSV могут выполняться с помощью стандартных функций Incanter, поэтомуполный пример выглядит так:
(use '(incanter core io)))
(def data (col-names (read-dataset 'data.csv') [:a :b])
(save (transform-rows :a #(* % 2) data) 'transformed-data.csv')