输入数字的平均值
Average of entered numbers
在这个程序中,我想得到输入数字的平均值,不仅是总和,而且我无法得到平均值,而且“输入数字:”不断重复。
这是我的代码
(princ"Enter how many numbers to read: ")
(defparameter a(read))
(defun num ()
(loop repeat a
sum (progn
(format *query-io* "Enter a number: ")
(finish-output)
(parse-integer (read-line *query-io* )))))
(format t "Sum: ~d ~%" (num))
(format t "Average: ~d ~%" (/ (num) a)) ;; I can't get the output for the average and the "Enter a number: " keeps repeating.
Enter how many numbers to read: 5
Enter a number: 4
Enter a number: 3
Enter a number: 2
Enter a number: 1
Enter a number: 3
Sum: 13
Enter a number: <-------
您的提示重复的原因是您的代码调用了 NUM
两次。每次调用 NUM
时,它都会要求更多输入。一个基本的修复方法是将程序中显示结果的部分包装在一个函数中,只需调用一次 NUM
并将结果绑定到一个变量:
(princ "Enter how many numbers to read: ")
(defparameter a (read))
(defun num ()
(loop repeat a
sum (progn
(format *query-io* "Enter a number: ")
(finish-output)
(parse-integer (read-line *query-io*)))))
(defun stats ()
(let ((sum (num)))
(format t "Sum: ~d ~%" sum)
(format t "Average: ~d ~%" (/ sum a))))
这“有效”,但是当加载代码时,系统会提示用户输入以设置 A
参数;然后用户需要调用 STATS
输入数据并查看结果。至少可以说这很尴尬。但是这个程序有很多小问题。以下是一些建议:
- 完全避免使用全局参数
- 调用
READ-LINE
而不是READ
来获取输入元素的计数
- 始终如一地使用
*QUERY-IO*
- 始终如一地调用
FINISH-OUTPUT
- 使用更好的变量名(
A
和 NUM
在这里描述性不强)
- 使用
~A
代替~D
平均值不能为整数;它可能是一小部分。当它的参数不是整数时,FORMAT
使用 ~A
代替 ~D
,但最好明确说明这一点。我只会在两行输出中使用 ~A
。
您可以编写一个函数来合并上述所有建议:
(defun stats ()
(format *query-io* "Enter how many numbers to read: ")
(finish-output *query-io*)
(let* ((count (parse-integer (read-line *query-io*)))
(sum
(loop repeat count
do (format *query-io* "Enter a number: ")
(finish-output *query-io*)
summing (parse-integer (read-line *query-io*)))))
(format *query-io* "Sum: ~A~%Average: ~A~%" sum (/ sum count))
(finish-output *query-io*)))
这里的COUNT
代替了之前的A
,是STATS
函数内的一个局部变量。使用 LET*
而不是 LET
以便 SUM
可以使用 COUNT
,但可以使用嵌套的 LET
表达式。请注意,SUM
绑定到循环的结果,这是 SUMMING
关键字的结果。 *QUERY-IO*
始终如一地使用,当其顺序很重要时,打印输出总是跟在 FINISH-OUTPUT
之后。
要进一步改进此代码,还有很多工作要做。此代码中没有输入验证;应该加上。最好将 STATS
分成更小的函数,将输入、计算和输出操作分开。能够处理输入和输出中的浮点数可能会很好。
交互示例:
CL-USER> (stats)
Enter how many numbers to read: 3
Enter a number: 1
Enter a number: 2
Enter a number: 2
Sum: 5
Average: 5/3
OP 在评论中提问:
I tried to add (min count) (max count)) in your given code to get the
minimum and maximum value but the output is the sum. How can I get
minimum and maximum number?
这确实是一个新问题,但它指出了上述函数设计中的缺点,这些缺点已通过“将 STATS
分解成更小的函数来暗示。 ..."
首先,请注意 (MIN COUNT)
或 (MAX COUNT)
不会有帮助,因为我们需要输入数据的最小值或最大值; COUNT
只是用户要输入的值的数量。原始代码直接对输入的值求和;一种更灵活的方法是将输入收集到一个列表中,然后对该列表进行操作以获得所需的结果。 MIN
和 MAX
函数对许多值进行操作,而不是对列表进行操作,因此我们需要使用 APPLY
将它们应用于结果列表。我们还可以将 +
应用于输入值列表以获得列表中元素的总和:
(defun stats ()
(format *query-io* "Enter how many numbers to read: ")
(finish-output *query-io*)
(let* ((count (parse-integer (read-line *query-io*)))
(data
(loop repeat count
do (format *query-io* "Enter a number: ")
(finish-output *query-io*)
collecting (parse-integer (read-line *query-io*))))
(min (apply #'min data))
(max (apply #'max data))
(sum (apply #'+ data))
(avg (float (/ sum count))))
(format *query-io* "Minimum: ~A~%" min)
(format *query-io* "Maximum: ~A~%" max)
(format *query-io* "Sum: ~A~%" sum)
(format *query-io* "Average: ~A~%" avg)
(finish-output *query-io*)))
这里循环使用COLLECTING
关键字将输入收集到列表中,结果绑定到DATA
。进行了所需的计算,并打印了结果。
这是可行的,但它真的是在乞求更好的设计;一个函数中发生了太多不同的事情。您可以将显示代码移动到另一个函数中,returning MIN
、MAX
等在列表中或作为多个值。但是,如果计算独立于通过允许 STATS
到 return 输入列表来收集输入的代码,那么它会更加灵活。 AVG
的计算需要COUNT
;新代码也可以 return COUNT
,但无论如何都不需要,因为我们可以在输入列表上调用 LENGTH
来获得计数。有人想知道为什么我们需要用户输入许多元素。如果我们在输入非数字值之前从用户那里获取数字怎么办?
这个答案已经很长了,但下面是一些将 STATS
函数分解成更小部分的代码,并在此过程中对其进行细化。通过使用更专注于其任务的更小的函数定义,函数可以被重用或与其他函数组合以更容易地完成其他目标,并且在需要更改时修改定义也将更容易。最后一个函数 PROMPT-FOR-STATS-REPORT
基本上完成了早期 STATS
函数所做的工作。现在通过修改 PROMPT-FOR-STATS
添加新功能要容易得多。扩充 PROMPT-FOR-STATS
时可以根据需要添加新的访问器函数,并且可以修改 PROMPT-FOR-STATS-REPORT
以不同方式显示结果,或者访问和显示新添加的功能。
如果有“最佳”解决方案,这绝不是OP问题的最佳解决方案。我鼓励 OP 尝试找到改进此代码设计的方法。有一些评论散落在各处:
;;; Here is a function to prompt for an integer. Since we want to receive
;;; non-numeric input `:JUNK-ALLOWED` is set to `T`. When input that can not be
;;; parsed into an integer is provided, `PARSE-INTEGER` will now return `NIL`
;;; instead of signalling an error condition.
(defun prompt-for-int (msg)
(format *query-io* "~A" msg)
(finish-output *query-io*)
(parse-integer (read-line *query-io*) :junk-allowed t))
;;; Here is a function to prompt for input until some non-numeric value
;;; is given. The results are collected in a list and returned.
(defun prompt-for-ints (msg)
(format *query-io* "~A~%" msg)
(finish-output *query-io*)
(let (input-num)
(loop
do (setf input-num (prompt-for-int "Enter a number ENTER to quit: "))
while input-num
collecting input-num)))
;;; Some functions to calculate statistics:
(defun count-of-nums (xs)
(length xs))
(defun min-of-nums (xs)
(apply #'min xs))
(defun max-of-nums (xs)
(apply #'max xs))
(defun sum-of-nums (xs)
(apply #'+ xs))
(defun avg-of-nums (xs)
(float (/ (sum-of-nums xs)
(count-of-nums xs))))
;;; A function to prompt the user for input which returns a list of statistics.
(defun prompt-for-stats (msg)
(let ((data (prompt-for-ints msg)))
(list (count-of-nums data)
(min-of-nums data)
(max-of-nums data)
(sum-of-nums data)
(avg-of-nums data))))
;;; Accessor functions for a list of statistics:
(defun get-stats-count (stats)
(first stats))
(defun get-stats-min (stats)
(second stats))
(defun get-stats-max (stats)
(third stats))
(defun get-stats-sum (stats)
(fourth stats))
(defun get-stats-avg (stats)
(fifth stats))
;;; A function that prompts for input and displays results.
(defun prompt-for-stats-report ()
(let ((results (prompt-for-stats "Enter some integers to view statistics")))
(format *query-io* "Count: ~A~%" (get-stats-count results))
(format *query-io* "Minimum: ~A~%" (get-stats-min results))
(format *query-io* "Maximum: ~A~%" (get-stats-max results))
(format *query-io* "Sum: ~A~%" (get-stats-sum results))
(format *query-io* "Average: ~A~%" (get-stats-avg results))
(finish-output *query-io*)))
交互示例:
CL-USER> (prompt-for-stats-report)
Enter some integers to view statistics
Enter a number ENTER to quit: 1
Enter a number ENTER to quit: 2
Enter a number ENTER to quit: 1
Enter a number ENTER to quit:
Count: 3
Minimum: 1
Maximum: 2
Sum: 4
Average: 1.3333334
在这个程序中,我想得到输入数字的平均值,不仅是总和,而且我无法得到平均值,而且“输入数字:”不断重复。
这是我的代码
(princ"Enter how many numbers to read: ")
(defparameter a(read))
(defun num ()
(loop repeat a
sum (progn
(format *query-io* "Enter a number: ")
(finish-output)
(parse-integer (read-line *query-io* )))))
(format t "Sum: ~d ~%" (num))
(format t "Average: ~d ~%" (/ (num) a)) ;; I can't get the output for the average and the "Enter a number: " keeps repeating.
Enter how many numbers to read: 5
Enter a number: 4
Enter a number: 3
Enter a number: 2
Enter a number: 1
Enter a number: 3
Sum: 13
Enter a number: <-------
您的提示重复的原因是您的代码调用了 NUM
两次。每次调用 NUM
时,它都会要求更多输入。一个基本的修复方法是将程序中显示结果的部分包装在一个函数中,只需调用一次 NUM
并将结果绑定到一个变量:
(princ "Enter how many numbers to read: ")
(defparameter a (read))
(defun num ()
(loop repeat a
sum (progn
(format *query-io* "Enter a number: ")
(finish-output)
(parse-integer (read-line *query-io*)))))
(defun stats ()
(let ((sum (num)))
(format t "Sum: ~d ~%" sum)
(format t "Average: ~d ~%" (/ sum a))))
这“有效”,但是当加载代码时,系统会提示用户输入以设置 A
参数;然后用户需要调用 STATS
输入数据并查看结果。至少可以说这很尴尬。但是这个程序有很多小问题。以下是一些建议:
- 完全避免使用全局参数
- 调用
READ-LINE
而不是READ
来获取输入元素的计数 - 始终如一地使用
*QUERY-IO*
- 始终如一地调用
FINISH-OUTPUT
- 使用更好的变量名(
A
和NUM
在这里描述性不强) - 使用
~A
代替~D
平均值不能为整数;它可能是一小部分。当它的参数不是整数时,FORMAT
使用 ~A
代替 ~D
,但最好明确说明这一点。我只会在两行输出中使用 ~A
。
您可以编写一个函数来合并上述所有建议:
(defun stats ()
(format *query-io* "Enter how many numbers to read: ")
(finish-output *query-io*)
(let* ((count (parse-integer (read-line *query-io*)))
(sum
(loop repeat count
do (format *query-io* "Enter a number: ")
(finish-output *query-io*)
summing (parse-integer (read-line *query-io*)))))
(format *query-io* "Sum: ~A~%Average: ~A~%" sum (/ sum count))
(finish-output *query-io*)))
这里的COUNT
代替了之前的A
,是STATS
函数内的一个局部变量。使用 LET*
而不是 LET
以便 SUM
可以使用 COUNT
,但可以使用嵌套的 LET
表达式。请注意,SUM
绑定到循环的结果,这是 SUMMING
关键字的结果。 *QUERY-IO*
始终如一地使用,当其顺序很重要时,打印输出总是跟在 FINISH-OUTPUT
之后。
要进一步改进此代码,还有很多工作要做。此代码中没有输入验证;应该加上。最好将 STATS
分成更小的函数,将输入、计算和输出操作分开。能够处理输入和输出中的浮点数可能会很好。
交互示例:
CL-USER> (stats)
Enter how many numbers to read: 3
Enter a number: 1
Enter a number: 2
Enter a number: 2
Sum: 5
Average: 5/3
OP 在评论中提问:
I tried to add (min count) (max count)) in your given code to get the minimum and maximum value but the output is the sum. How can I get minimum and maximum number?
这确实是一个新问题,但它指出了上述函数设计中的缺点,这些缺点已通过“将 STATS
分解成更小的函数来暗示。 ..."
首先,请注意 (MIN COUNT)
或 (MAX COUNT)
不会有帮助,因为我们需要输入数据的最小值或最大值; COUNT
只是用户要输入的值的数量。原始代码直接对输入的值求和;一种更灵活的方法是将输入收集到一个列表中,然后对该列表进行操作以获得所需的结果。 MIN
和 MAX
函数对许多值进行操作,而不是对列表进行操作,因此我们需要使用 APPLY
将它们应用于结果列表。我们还可以将 +
应用于输入值列表以获得列表中元素的总和:
(defun stats ()
(format *query-io* "Enter how many numbers to read: ")
(finish-output *query-io*)
(let* ((count (parse-integer (read-line *query-io*)))
(data
(loop repeat count
do (format *query-io* "Enter a number: ")
(finish-output *query-io*)
collecting (parse-integer (read-line *query-io*))))
(min (apply #'min data))
(max (apply #'max data))
(sum (apply #'+ data))
(avg (float (/ sum count))))
(format *query-io* "Minimum: ~A~%" min)
(format *query-io* "Maximum: ~A~%" max)
(format *query-io* "Sum: ~A~%" sum)
(format *query-io* "Average: ~A~%" avg)
(finish-output *query-io*)))
这里循环使用COLLECTING
关键字将输入收集到列表中,结果绑定到DATA
。进行了所需的计算,并打印了结果。
这是可行的,但它真的是在乞求更好的设计;一个函数中发生了太多不同的事情。您可以将显示代码移动到另一个函数中,returning MIN
、MAX
等在列表中或作为多个值。但是,如果计算独立于通过允许 STATS
到 return 输入列表来收集输入的代码,那么它会更加灵活。 AVG
的计算需要COUNT
;新代码也可以 return COUNT
,但无论如何都不需要,因为我们可以在输入列表上调用 LENGTH
来获得计数。有人想知道为什么我们需要用户输入许多元素。如果我们在输入非数字值之前从用户那里获取数字怎么办?
这个答案已经很长了,但下面是一些将 STATS
函数分解成更小部分的代码,并在此过程中对其进行细化。通过使用更专注于其任务的更小的函数定义,函数可以被重用或与其他函数组合以更容易地完成其他目标,并且在需要更改时修改定义也将更容易。最后一个函数 PROMPT-FOR-STATS-REPORT
基本上完成了早期 STATS
函数所做的工作。现在通过修改 PROMPT-FOR-STATS
添加新功能要容易得多。扩充 PROMPT-FOR-STATS
时可以根据需要添加新的访问器函数,并且可以修改 PROMPT-FOR-STATS-REPORT
以不同方式显示结果,或者访问和显示新添加的功能。
如果有“最佳”解决方案,这绝不是OP问题的最佳解决方案。我鼓励 OP 尝试找到改进此代码设计的方法。有一些评论散落在各处:
;;; Here is a function to prompt for an integer. Since we want to receive
;;; non-numeric input `:JUNK-ALLOWED` is set to `T`. When input that can not be
;;; parsed into an integer is provided, `PARSE-INTEGER` will now return `NIL`
;;; instead of signalling an error condition.
(defun prompt-for-int (msg)
(format *query-io* "~A" msg)
(finish-output *query-io*)
(parse-integer (read-line *query-io*) :junk-allowed t))
;;; Here is a function to prompt for input until some non-numeric value
;;; is given. The results are collected in a list and returned.
(defun prompt-for-ints (msg)
(format *query-io* "~A~%" msg)
(finish-output *query-io*)
(let (input-num)
(loop
do (setf input-num (prompt-for-int "Enter a number ENTER to quit: "))
while input-num
collecting input-num)))
;;; Some functions to calculate statistics:
(defun count-of-nums (xs)
(length xs))
(defun min-of-nums (xs)
(apply #'min xs))
(defun max-of-nums (xs)
(apply #'max xs))
(defun sum-of-nums (xs)
(apply #'+ xs))
(defun avg-of-nums (xs)
(float (/ (sum-of-nums xs)
(count-of-nums xs))))
;;; A function to prompt the user for input which returns a list of statistics.
(defun prompt-for-stats (msg)
(let ((data (prompt-for-ints msg)))
(list (count-of-nums data)
(min-of-nums data)
(max-of-nums data)
(sum-of-nums data)
(avg-of-nums data))))
;;; Accessor functions for a list of statistics:
(defun get-stats-count (stats)
(first stats))
(defun get-stats-min (stats)
(second stats))
(defun get-stats-max (stats)
(third stats))
(defun get-stats-sum (stats)
(fourth stats))
(defun get-stats-avg (stats)
(fifth stats))
;;; A function that prompts for input and displays results.
(defun prompt-for-stats-report ()
(let ((results (prompt-for-stats "Enter some integers to view statistics")))
(format *query-io* "Count: ~A~%" (get-stats-count results))
(format *query-io* "Minimum: ~A~%" (get-stats-min results))
(format *query-io* "Maximum: ~A~%" (get-stats-max results))
(format *query-io* "Sum: ~A~%" (get-stats-sum results))
(format *query-io* "Average: ~A~%" (get-stats-avg results))
(finish-output *query-io*)))
交互示例:
CL-USER> (prompt-for-stats-report)
Enter some integers to view statistics
Enter a number ENTER to quit: 1
Enter a number ENTER to quit: 2
Enter a number ENTER to quit: 1
Enter a number ENTER to quit:
Count: 3
Minimum: 1
Maximum: 2
Sum: 4
Average: 1.3333334