我是一个Clojure新手,并且在其不可变状态方面遇到了麻烦。我正在尝试编写一个带有保龄球游戏框架列表的函数。例如,列表看起来像[" X" " 12" " 2 /" " X" " 45" " X" " 13" " 33" " X" " 81&#34]。我希望函数输出一个列表来处理只有整数的帧,并将这些数字加在一起。因此,如果输入上面的列表,将输出以下列表:[" X" " 3" " 2 /" " X" " 9" " X" " 4" " 6" " X" " 9&#34]。这是我的尝试,但Clojure中的不可变状态让我很难理解如何解决这个问题:
(defn eval-frames
[flist]
(loop [frames '()]
(if (not (= flist '()))
frames
(eval-normal (rest flist)))
(if (not (or (spare? flist) (strike? flist) (= flist ())))
(conj frames (+ (get (first flist) 0) ((get (first flist) 1))))
(conj frames (first flist)))
)
)
这最终会输出列表中的第一帧,而不是整个列表。任何建议都将非常感谢!
答案 0 :(得分:1)
您发布的代码存在相当大的错误:
整个(if (not (= flist '()))
部分什么都不做,因为你从不使用它给出的结果。你在这里想得太多了。 conj
返回“已修改”列表,但不会更改原始列表!
recur
中永远不会loop
,因此loop
只会运行一次。
我只是使用map
。它遍历列表,并根据函数“转换”每个元素。我 高度 建议您尽可能使用map
和reduce
,因为您将不断使用它们。
我的计划是:
如果框架中的所有字符都是数字,请对框架求和,否则,请保留框架。
要对帧进行求和,我使用parseLong
将每个字符转换为数字,然后(apply +
将已解析的数字相加,然后str
将其转换为数字回到一个字符串。
(map
(fn [frame]
; Almost reads like English!
(if (every? #(Character/isDigit %) frame)
(->> frame ; Take the frame...
(map #(Long/parseLong (str %))) ; parse each character in the frame...
(apply +) ; then sum the parsed numbers...
(str)) ; and turn them back into a string.
frame)) ; Else, do nothing and leave the frame alone
["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"])
=> ("X" "3" "2/" "X" "9" "X" "4" "6" "X" "9")
如果你已经将分数存储为最初的数字而不是将它们转换为字符串,那么这会有所简化。这样可以避免需要Long/parseLong
,最后调用str
将每个求和的帧重新转换为字符串。
答案 1 :(得分:1)
(map #(if (every? (fn [c] (<= (int \0) (int c) (int \9))) %)
(str (apply + (map read-string (map str %))))
%)
["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"])
或没有读取字符串:
(map #(if (every? (fn [c] (<= (int \0) (int c) (int \9))) %)
(str (apply + (map (fn [c] (- (int c) (int \0))) %)))
%)
["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"])
=&GT; (&#34; X&#34;&#34; 3&#34;&#34; 2 /&#34;&#34; X&#34;&#34; 9&#34;&#34; X&#34 ;&#34; 4&#34;&#34; 6&#34;&#34; X&#34;&#34; 9&#34;)
答案 2 :(得分:0)
(defn eval-frames [frames]
(map #(if (re-find #"\d\d" %)
(reduce + (map (fn [i](Integer. (str i))) (seq %))) %) frames))
所以用给定的框架进行评估会得到:
(eval-frames ["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"])
=> ("X" "3" "2/" "X" "9" "X" "4" "6" "X" "9")