【问题标题】:Sum of numbers in a list from user input来自用户输入的列表中的数字总和
【发布时间】:2018-01-19 17:38:34
【问题描述】:

来自 Clojure 新手的问题。任务非常简单,但我很难找到最好的方法来做到这一点 - 我需要设置输入,用户可以在其中给我一个自然数列表(用户应该确定多长时间)并且程序应该只返回这些数字的总和。

也许这已经完全错误了:

(defn inputlist[naturallist]
  (println "Enter list of natural numbers:") 
  (let[naturallist(read-line)] ))

【问题讨论】:

    标签: list clojure


    【解决方案1】:

    这是一种方法:

    > lein new app demo
    > cd demo
    

    编辑project.cljsrc/demo/core.clj,使其如下所示:

    > cat project.clj
    
    (defproject demo "0.1.0-SNAPSHOT"
      :description "FIXME: write description"
      :url "http://example.com/FIXME"
      :license {:name "Eclipse Public License"
                :url "http://www.eclipse.org/legal/epl-v10.html"}
      :dependencies [[org.clojure/clojure "1.9.0"]
                     [org.clojure/tools.reader "1.1.3.1"] ]
      :main ^:skip-aot demo.core
      :target-path "target/%s"
      :profiles {:uberjar {:aot :all}})
    
    > cat src/demo/core.clj 
    
    (ns demo.core
      (:require
        [clojure.tools.reader.edn :as edn]
        [clojure.string :as str]  ))
    
    (defn -main []
      (println "enter numbers")
      (let [input-line (read-line)
            num-strs   (str/split input-line #"\s+")
            nums       (mapv edn/read-string num-strs)
            result     (apply + nums) ]
        (println "result=" result)))
    

    结果

    > lein run
    enter numbers
    1 2 3     <= you type this, then <enter>
    
    input-line   => "1 2 3"
    num-strs     => ["1" "2" "3"]
    nums         => [1 2 3]
    result       => 6
    

    您可能也希望开始查看一些初学者书籍:

    【讨论】:

    • 嗨!尝试了这段代码,第一次遇到了关于使用 tupelo 的错误,添加了依赖项,现在我得到了: CompilerException java.lang.RuntimeException: Unable to resolve symbol: defproject in this context, compile:(C:\Users\...\ project.clj:1:1)
    • 我更新了示例。使 project.cljsrc/demo/core.clj 看起来像示例,它应该适合你。
    • 现在工作正常!非常感谢!得到了除了 project.clj 的最后 3 行之外的所有内容。谷歌一下,谢谢!
    【解决方案2】:

    我能想到的最快的方法是

    #(apply + (map #(Integer/parseInt %) (re-seq #"\d+" (read-line))))
    

    这定义了一个匿名函数:

    • (read-line) - 读取一行文本,希望包含由非数字字符分隔的数字。所以你输入类似“123 456 789”的内容
    • (re-seq #"\d+" ...) - 使用正则表达式 \d+ 搜索连续数字的字符串。每个连续数字的字符串都被添加到一个序列中,该序列随后被返回。因此,例如,如果您输入 123, 456, 789re-seq 函数将返回序列 '("123" "456" "789")
    • (map #(Integer/parseInt %) ...) - 为re-seq 调用返回的列表中的每个元素调用匿名函数#(Integer/parseInt %),创建另一个结果列表。因此,如果输入为'("123" "456" "789"),则输出将为'(123 456 789)
    • (apply + ...) - 将+ 函数应用于数字列表,将它们相加,然后返回总和。

    瞧!最终结果是,你输入一串数字,用非数字字符分隔,你会得到这些数字的总和。如果你想更整洁一点,促进代码重用,并且总的来说让它更有用,你可以把它分解成单独的函数:

    (defn parse-string-list [s]
      (re-seq #"\d+" s))
    
    (defn convert-seq-of-int-strings [ss]
      (map #(Integer/parseInt %) ss))
    
    (defn sum-numbers-in-seq [ss]
      (apply + ss))
    

    以 Lisp-y 的方式调用它看起来像

    (sum-numbers-in-seq (convert-seq-of-int-strings (parse-string-list (read-line))))
    

    或者,以更 Clojure-y 的方式

    (-> (read-line)
        (parse-string-list)
        (convert-seq-of-int-strings)
        (sum-numbers-in-seq))
    

    祝你好运。

    【讨论】:

      【解决方案3】:

      欢迎使用 Clojure 和 StackOverflow!

      这是怎么做的:

      (defn input-numbers-and-sum []
        (print "Enter list of natural numbers: ")
        (flush)
        (->> (clojure.string/split (read-line) #"\s+")
             (map #(Integer/parseInt %))
             (reduce +)))
      

      它是这样工作的:

      • 调用print 而不是println 可以避免在行尾打印换行符。这样,用户的输入将与您的提示出现在同一行。

      • 由于没有换行符,您必须调用 flush 来强制打印包含提示的输出缓冲区。

      • split 将用户键入的内容拆分为字符串序列,在正则表达式匹配的位置进行划分。你必须说clojure.string/split 而不仅仅是split,因为split 不在Clojure 的core library 中。 clojure.string/ 指定 the library#"\s+" 是一个匹配任意数量的连续空白字符的regular expression。因此,如果您的用户输入 "  6 82   -15   "split 将返回 ["6" "82" "-15"]

      • map 对每个字符串调用标准 Java 库函数 Integer.parseIntInteger/parseInt 是 Clojure 的 Java interop 语法,用于调用 Java 类的静态方法。 #(...) 是定义匿名函数的简洁语法; % 是传递给该函数的参数。因此,给定上面的字符串序列,对map 的调用将返回一个整数序列:[6 82 -15]

      • reduce 对整数序列的每个元素重复调用 + 函数,将总和作为参数与下一个整数一起传递。 mapreduce 实际上接受三个参数;下一段讲述第三段是如何填写的。

      • -&gt;&gt; 是“线程最后的宏”。它重写其中的代码,以传递每个表达式的输出,但最后一个表达式作为以下表达式的最后一个参数。结果是:

        (reduce + (map #(Integer/parseInt %) (clojure.string/split (read-line) #"\s+")))

        大多数人发现-&gt;&gt; 的版本更容易阅读。

      做一些非常简单的事情可能看起来很多,但一旦你习惯了 Clojure,它实际上就是面包和黄油。 Clojure 旨在使事物易于组合; mapreduce-&gt;&gt; 是用于将其他功能连接在一起的特别有用的工具。

      我已经包含了文档的链接。这些值得一看;许多包含典型的使用示例。

      当然还有其他解析数字的方法,其中一些在this question的答案中有所展示。我上面写的是一种“惯用的”方法。了解这一点,您就会了解很多日常使用 Clojure 编程的必知技巧。

      【讨论】:

        【解决方案4】:

        是的,readline 是正确的方法。 但是 readlines 中的每个元素本质上都是 java.lang.Character 的一个实例,并且由于您想要求和,因此您希望在对列表的元素求和之前将它们转换为整数。

        (defn input-list
          []
          (print "Enter list of natural numbers") 
          (let [nums (read-line)] 
            (reduce + (map #(Integer/parseInt %) (clojure.string/split nums #"\s+")))
        

        这可能不是最惯用的方法,但可以随意调整。

        另外,请清理您的变量/函数名称。

        编辑(Integer/parseInt %) 如果直接使用可能会导致错误,因为输入是字符的实例,而不是字符串。所以我们可以使用clojure.string/split将用户输入转换为字符串序列,使用Integer/parseInt %进行转换。

        事实上,更易读的版本可以使用线程优先的宏来编写:

        (defn input-list []
          (print "Enter list of natural numbers: ")
          (->> (clojure.string/split (read-line) #"\s+")
               (map #(Integer/parseInt %))
               (reduce +))) 
        

        这是一种更符合 clojurey 的方法。

        【讨论】:

        • 出现错误。转换有问题? : ClassCastException java.lang.Character 无法转换为 java.lang.String
        • 是的,用户输入的是字符序列,在使用 #(Integer/parseInt %) 之前需要转换为字符串序列。已经修好了。感谢您指出。 @kjankausks
        • 现在可以了!也很容易理解,谢谢@namc!
        【解决方案5】:

        如果您不关心负面情况(错误输入、语法问题),最快的解决方案是评估用户的输入并将其放入括号中:

        (defn sum-ints []
          (let [input (read-line)
                ints (read-string (str "(" input ")"))]
            (reduce + 0 ints)))
        

        用法:

        user=> (sum-ints)
        1 2 3 4 5
        15
        

        read-string 函数在这种情况下计算文本表达式 (1 2 3 4 5)。由于数字文字会变成数字,因此结果将只是一个数字列表。

        【讨论】:

          猜你喜欢
          • 2021-11-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-12-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多