【问题标题】:Returning a string in a function in Clojure在 Clojure 的函数中返回一个字符串
【发布时间】:2020-03-09 18:50:54
【问题描述】:

当我读取这个包含城市和城市属性的 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

我可以让它打印出该行,但是如果这有意义的话,我将如何让该函数返回该行?

【问题讨论】:

    标签: string function clojure return


    【解决方案1】:

    println 函数用于处理副作用,并且始终返回 nil。调整您的函数以将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]
    

    【讨论】:

      【解决方案2】:

      根据您目前的代码设置方式,您不能。 doseq 是用来执行副作用的;它不返回任何东西。您很少想使用doseq,也很少应该在函数定义中使用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 迭代之前请求第一个元素,一旦找到匹配的行就不再进行迭代。

      【讨论】:

      • 感谢您的帮助
      • 当我尝试将此应用于应该返回 csv 文件中所有城市记录的函数时,它不会返回?这就是我所拥有的 (defn city [] (with-open [rdr (reader)] (first (for [line (drop 1 (line-seq rdr))] line))))
      • @RichardDesouza 它必须返回。唯一无法返回的方法是line-seq 返回的序列是无限的,我认为这是不可能的。如果您想返回所有城市,请将呼叫更改为 firstvecfirst 将导致它停止查看我在帖子中提到的第一个发现。
      • @RichardDesouza 我还要注意,如果你想返回所有行,你也可以只使用函数 return (vec (drop 1 (line-seq rdr)))。使用for 只是重复line-seq 返回的数据是没有意义的。
      • 谢谢它的工作我现在可以返回所有的值。只是另一个问题。我将其中一行保存在哈希图中。如何创建一个从 hashmap 中的键返回值的函数?
      猜你喜欢
      • 1970-01-01
      • 2012-03-30
      • 2021-09-27
      • 2013-04-14
      • 1970-01-01
      • 2012-03-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多