Proszę nie używać zagnieżdżonych def tych. Nie robi, co myślisz, że robi. def jest zawsze globalny! W przypadku mieszkańców użyj let zamiast tego. Podczas gdy funkcje biblioteczne są dobrze znane, tutaj jest wersja, która aranżuje niektóre funkcje programowania funkcjonalnego w ogóle, a w szczególności clojure.
(import 'java.io.FileWriter 'java.io.FileReader 'java.io.BufferedReader)
(defn translate-coords
Docfrings można uzyskać w REPL poprzez (doc translate-coords). Działa np. dla wszystkich podstawowych funkcji. Dostarczanie jednego jest dobrym pomysłem.
tłumacz to funkcja (może anonimowa), która wyodrębnia tłumaczenie z otaczającego zestawu znaków. Możemy więc ponownie użyć tych funkcji z różnymi regułami transformacji. Wskazówki dotyczące tego typu pozwalają uniknąć refleksji dla konstruktorów.
[translator #^String infile #^String outfile]
Otwórz pliki. with-open będzie dbał o to, aby pliki były zamykane po opuszczeniu jego ciała. Czy to przez normalne "upuszczanie na dół", czy to przez wyrzucony wyjątek.
(with-open [in (BufferedReader. (FileReader. infile))
out (FileWriter. outfile)]
Powiązanie strumienia *out*
tymczasowo z plikiem wyjściowym. Tak więc każdy wydruk wewnątrz wiązania będzie drukował do pliku.
(binding [*out* out]
W map
oznacza: wziąć nast i zastosować daną funkcję do każdego elementu i zwraca nast wyników. #()
to notacja krótka dla anonimowej funkcji. Potrzeba jednego argumentu, który jest wypełniony na %
. doseq
jest w zasadzie pętlą nad wejściem. Ponieważ robimy to dla efektów ubocznych (mianowicie drukowania do pliku), doseq
jest właściwą konstrukcją. Zasada kciuka: map
: leniwy => dla wyniku, doseq
: chętny => dla efektów ubocznych.
(doseq [coords (map #(.split % ",") (line-seq in))]
println
dba o \n
na końcu linii. interpose
przyjmuje seq i dodaje pierwszy argument (w naszym przypadku "") między jego elementami. (apply str [1 2 3])
jest odpowiednikiem (str 1 2 3)
i jest użyteczne do dynamicznego konstruowania wywołań funkcji. ->>
to stosunkowo nowe makro w clojure, które pomaga nieco w czytelności. Oznacza to "weź pierwszy argument i dodaj go jako ostatni element do wywołania funkcji". Podany ->>
jest równoważny z: (println (apply str (interpose " " (translator coords))))
. (Edit: Kolejna uwaga: ponieważ separator jest \space
moglibyśmy tu napisać równie dobrze (apply println (translator coords))
, ale wersja interpose
pozwala również parametrize separator jak my z funkcją tłumacz, natomiast wersja skrócona będzie przewodowego \space
.)
(->> (translator coords)
(interpose " ")
(apply str)
println)))))
(defn survey->cartography-format
"Translate coords in survey format to cartography format."
Tutaj używamy destrukturyzacji (uwaga podwójna [[]]
). Oznacza to, że argument funkcji jest czymś, co można przekształcić w seq, np. wektor lub listę. Przypisz pierwszy element do y
, drugi do x
i tak dalej.
[[y x z p]]
[p x y z])
(translate-coords survey->cartography-format "survey_coords.txt" "cartography_coords.txt")
Tu znowu mniej wzburzony:
(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")
Nadzieja to pomaga.
Edycja: Do odczytu CSV prawdopodobnie potrzebujesz czegoś takiego jak OpenCSV.
'my ($ x, $ y, $ z, $ p) = split /, /;' –
Dobra uwaga - TIMTOWTDI. Dzięki. –