[英]Returning a string in a function in Clojure
當我閱讀這個包含城市和城市屬性的 CSV 文件時,我試圖返回一個字符串值。 這是我到目前為止所擁有的:
(defn city [name]
(with-open [rdr (reader)]
(doseq [line (drop 1 (line-seq rdr))]
(def x2 line)
(def y (string/split x2 #","))
(if (= name (y 0))
(println line)
))))
(city "Toronto")
=> Toronto,43.666667,-79.416667,Canada,CA,Ontario,admin,5213000,3934421
我可以讓它打印出該行,但是如果這有意義的話,我將如何讓 function 返回該行?
根據您當前的代碼設置方式,您不能。 doseq
是為了產生副作用; 它不返回任何東西。 您很少想使用doseq
,也很少會在 function 定義中使用def
。
您想找到(= name (y 0))
為真的第一行。 有幾種方法可以解決這個問題。 一種基本的方法是使用loop
,一旦找到線路就停止它。 我認為使用map
或for
循環line-seq
,然后在這里獲取第一個結果會很好:
(defn city [name]
(with-open [rdr (reader)]
(first
(for [line (drop 1 (line-seq rdr)) ; Same syntax here as with doseq
:let [y (string/split line #",")] ; Use let instead of def for local definitions
:when (= name (y 0))] ; Only add to the list ":when (= name (y 0))"
line))))
for
就像 Python 的生成器表達式(如果您熟悉 Python)。 它不像Java for
的正常循環命令。 for
將返回(= name (y 0))
為真的行列表。 因為可能文件中只有一個這樣的有效行,我們只想要一個結果,所以我們將列表傳遞給first
以獲取找到的第一個有效行。
請注意, for
是懶惰的。 這不會在傳遞給first
之前迭代整個文件。 first
請求for
之前的第一個元素甚至已經迭代,一旦找到匹配的行就不再進行迭代。
println
function 用於副作用,並且總是返回nil
。 調整您的 function 以返回line
作為if
之后的最后一項:
(if (= name (y 0))
line)
如果你還沒有看過,請看
這是代碼組織更好的版本。 您的項目依賴項將需要如下所示:
:dependencies [
[org.clojure/clojure "1.10.1"]
[prismatic/schema "1.1.12"]
[tupelo "0.9.168"]
]
然后代碼看起來像:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[clojure.string :as str]
[clojure.java.io :as io]
[tupelo.string :as ts]))
(def city-data
" city,lat,lon,country,ccode,province,unk1,unk2,unk3
Toronto,43.666667,-79.416667,Canada,CA,Ontario,admin,5213000,3934421
Chicago,40.666667,-99.416667,USA,US,dummy,admin,5213000,3934421
")
(defn city->fields [city-str]
(str/split city-str #","))
(defn city [name]
(with-open [rdr (io/reader (ts/string->stream city-data))]
(let [lines (mapv str/trim (line-seq rdr))
hdrs-line (first lines)
city-lines (rest lines)
cities-fields (mapv city->fields city-lines)
city-match (first (filterv #(= name (first %)) cities-fields))]
; debug printouts
(spyx hdrs-line)
(spyx-pretty city-lines)
(spyx city-match)
city-match))) ; <= return value
(dotest
(println "Result: " (city "Toronto"))
)
結果:
-------------------------------
Clojure 1.10.1 Java 13
-------------------------------
Testing tst.demo.core
hdrs-line => "city,lat,lon,country,ccode,province,unk1,unk2,unk3"
city-lines =>
("Toronto,43.666667,-79.416667,Canada,CA,Ontario,admin,5213000,3934421"
"Chicago,40.666667,-99.416667,USA,US,dummy,admin,5213000,3934421"
"")
city-match => ["Toronto" "43.666667" "-79.416667" "Canada" "CA" "Ontario" "admin" "5213000" "3934421"]
Result: [Toronto 43.666667 -79.416667 Canada CA Ontario admin 5213000 3934421]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.