簡體   English   中英

在 Clojure 中返回 function 中的字符串

[英]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 ,一旦找到線路就停止它。 我認為使用mapfor循環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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM