用户输入列表中的数字总和

时间:2018-01-19 17:38:35

标签: list clojure

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

也许这已经完全错了:

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

5 个答案:

答案 0 :(得分:4)

这是一种方法:

> 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

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

答案 1 :(得分:2)

我能想到的最快捷的方法是

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

这定义了一个匿名函数:

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

祝你好运。

答案 2 :(得分:1)

欢迎来到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实际上有三个论点;下一段说明如何填写第三段。

  • ->>是“线程最后一个宏”。它重写其中的代码,传递每个表达式的输出,但最后一个作为下面表达式的最后一个参数。结果是:
    (reduce + (map #(Integer/parseInt %) (clojure.string/split (read-line) #"\s+")))

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

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

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

还有其他解析数字的方法,当然,其中一些方法会显示在this question的答案中。我上面写的是一种“惯用”的方式。了解这一点,您将了解Clojure中许多日常必备技术。

答案 3 :(得分:0)

是的,readline是正确的方法。 但是readlines中的每个元素本质上都是java.lang.Character的一个实例,并且因为你想要总和,所以你更喜欢在对list的元素求和之前将它们转换为整数。

(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 +))) 

这是一种更为完美的方式。

答案 4 :(得分:0)

如果您不关心负面情况(错误的输入,语法问题),最快的解决方案是评估用户输入的内容:

(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)。由于数字文字变成数字,结果将只是一个数字列表。