. . . . . . . . . . . . . . . . . . . . . . . . . .
Было трудно заставить его отображаться здесь правильно, но теперь я попытался скопировать его из предварительного просмотра, и он работает. Вам нужно ввести номер и нажать Enter.
Пожалуйста, не используйте вложенные def. Он не делает того, что вы думаете. def всегда глобален! Для местных жителей используйте let. Хотя о библиотечных функциях приятно знать, вот версия, управляющая некоторыми особенностями функционального программирования в целом и Clojure в частности.
(import 'java.io.FileWriter 'java.io.FileReader 'java.io.BufferedReader)
(defn translate-coords
Строки документов можно запросить в REPL через (doc translate-coords). Работает напр. для всех основных функций. Так что предоставить его - хорошая идея.
"Reads coordinates from infile, translates them with the given
translator and writes the result to outfile."
translator - это (возможно, анонимная) функция, которая извлекает перевод из окружающего шаблона. Таким образом, мы можем повторно использовать эти функции с другими правилами преобразования. Подсказки типа здесь избегают отражения для конструкторов.
[translator #^String infile #^String outfile]
Откройте файлы. with-open позаботится о том, чтобы файлы были закрыты, когда его тело оставлено. Будь то через обычное "падение с дна" или через выброшенное исключение.
(with-open [in (BufferedReader. (FileReader. infile))
out (FileWriter. outfile)]
Мы временно привязываем поток * out *
к выходному файлу. Таким образом, любая печать внутри привязки будет напечатана в файл.
(binding [*out* out]
Карта
означает: взять последовательность и применить данную функцию к каждому элементу и вернуть последовательность результатов. # ()
- это сокращенное обозначение анонимной функции. Требуется один аргумент, который заполняется на %
. dosq
в основном представляет собой цикл над входом. Поскольку мы делаем это для побочных эффектов (а именно, для печати в файл), dosq
является правильной конструкцией. Практическое правило: map
: lazy => для результата, dosq
: eager => для побочных эффектов.
(doseq [coords (map #(.split % ",") (line-seq in))]
println
заботится о \ n
в конце строки. interpose
берет seq и добавляет первый аргумент (в нашем случае "") между его элементами. (применить str [1 2 3])
эквивалентно (str 1 2 3)
и полезно для динамического создания вызовов функций. - >>
- относительно новый макрос в clojure, который немного улучшает читаемость. Это означает «взять первый аргумент и добавить его в качестве последнего элемента к вызову функции». Данный - >>
эквивалентен: (println (apply str (interpose "" (координаты переводчика))))
. (Edit: еще одно примечание: поскольку разделителем является \ space
, мы могли бы здесь написать точно так же (применить println (координаты переводчика))
, но версия interpose
позволяет также параметризовать разделитель, как мы делали с функцией транслятора, в то время как короткая версия будет жестко подключаться \ space
.)
(->> (translator coords)
(interpose " ")
(apply str)
println)))))
(defn survey->cartography-format
"Translate coords in survey format to cartography format."
Здесь мы используем деструктурирование (обратите внимание на двойной [[]]
). Это означает, что аргумент функции - это то, что можно превратить в seq, например. вектор или список. Привяжите первый элемент к y
, второй к x
и т. Д.
[[y x z p]]
[p x y z])
(translate-coords survey->cartography-format "survey_coords.txt" "cartography_coords.txt")
Здесь снова менее изменчиво:
(import 'java.io.FileWriter 'java.io.FileReader 'java.io.BufferedReader)
(defn translate-coords
"Reads coordinates from infile, translates them with the given
translator and writes the result to outfile."
[translator #^String infile #^String outfile]
(with-open [in (BufferedReader. (FileReader. infile))
out (FileWriter. outfile)]
(binding [*out* out]
(doseq [coords (map #(.split % ",") (line-seq in))]
(->> (translator coords)
(interpose " ")
(apply str)
println)))))
(defn survey->cartography-format
"Translate coords in survey format to cartography format."
[[y x z p]]
[p x y z])
(translate-coords survey->cartography-format "survey_coords.txt" "cartography_coords.txt")
Надеюсь, это поможет.
Изменить: для чтения CSV вам, вероятно, понадобится что-то вроде OpenCSV.
Вот один способ:
(use '(clojure.contrib duck-streams str-utils)) ;;'
(with-out-writer "coords.txt"
(doseq [line (read-lines "coords.csv")]
(let [[x y z p] (re-split #"," line)]
(println (str-join \space [p x y z])))))
with-out-writer
связывает * out *
так, что все, что вы печатаете, будет идти в указанное вами имя файла или поток, а не стандартный вывод.
Использование def
в том виде, в котором вы его используете, не является идиоматическим. Лучше использовать let . Я использую деструктурирование, чтобы присвоить 4 полям каждой строки 4 let
-связанных имен; тогда вы можете делать с ними все, что хотите.
Если вы повторяете что-то с целью побочных эффектов (например, ввода-вывода), вам обычно следует использовать dosq
. Если вы хотите собрать каждую строку в хэш-карту и что-то с ней сделать позже, вы можете использовать вместо
:
(with-out-writer "coords.txt"
(for [line (read-lines "coords.csv")]
(let [fields (re-split #"," line)]
(zipmap [:x :y :z :p] fields))))