Clojure:操作列表

时间:2018-03-12 00:47:33

标签: clojure

我是一个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)))
  )
)

这最终会输出列表中的第一帧,而不是整个列表。任何建议都将非常感谢!

3 个答案:

答案 0 :(得分:1)

您发布的代码存在相当大的错误:

  • 整个(if (not (= flist '()))部分什么都不做,因为你从不使用它给出的结果。你在这里想得太多了。 conj返回“已修改”列表,但不会更改原始列表!

  • recur中永远不会loop,因此loop只会运行一次。

我只是使用map。它遍历列表,并根据函数“转换”每个元素。我 高度 建议您尽可能使用mapreduce,因为您将不断使用它们。

我的计划是:

  • 如果框架中的所有字符都是数字,请对框架求和,否则,请保留框架。

  • 要对帧进行求和,我使用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")