使用重复时返回 else 值

  • 本文关键字:返回 else clojure
  • 更新时间 :
  • 英文 :


我是Clojure的新手,我尽力忘记我以前使用更多过程语言(java,ruby,swift(的所有经验,并拥抱Clojure。实际上,我真的很享受它让我以不同的方式思考的方式 - 然而,我遇到了一个我似乎无法弄清楚的模式。最简单的说明方法是使用一些代码:

(defn char-to-int [c] (Integer/valueOf (str c)))
(defn digits-dont-decrease? [str]
(let [digits (map char-to-int (seq str)) i 0]
(when (< i 5)
(if (> (nth digits i) (nth digits (+ i 1)))
false
(recur (inc i))))))
(def result (digits-dont-decrease? "112233"))
(if (= true result)
(println "fit rules")
(println "doesn't fit rules"))

输入是一个 6 位数字作为字符串,我只是试图确保从左到右的每个数字都是>= 前一个数字。如果没有,我想返回 false,如果返回 true,则返回 true。错误的情况效果很好 - 但是,鉴于recur需要成为函数中的最后一件事(据我所知(,我如何返回 true。实际上,当满足条件时,我得到一个非法的参数异常:

Execution error (IllegalArgumentException) at clojure.exercise.two/digits-dont-decrease? (four:20).
Don't know how to create ISeq from: java.lang.Long

我应该如何考虑这个问题?我认为我过去的训练妨碍了我的精神。

这不是在回答你的问题,但也显示了另一种选择。 虽然整个琴弦的(apply < ...)方法对于小弦来说非常优雅(它很急切(,但您可以使用every?进行短路方法。 例如:

user=> (defn nr-seq [s] (map #(Integer/parseInt (str %)) s))
#'user/nr-seq
user=> (every? (partial apply <=) (partition 2 1 (nr-seq "123")))
true

你只需要

(apply <= "112233")

原因:字符串是字符序列,比较运算符适用于字符。

(->> "0123456789" (mapcat #(repeat 1000 %)) (apply str) (def loooong))
(count loooong)
10000
(time (apply <= loooong))
"Elapsed time: 21.006625 msecs"
true
(->> "9123456789" (mapcat #(repeat 1000 %)) (apply str) (def bad-loooong))
(count bad-loooong)
10000
(time (apply <= bad-loooong))
"Elapsed time: 2.581750 msecs"
false

(以上运行在我的iPhone上(

在这种情况下,你并不真正需要循环/重复。 只需像这样使用<=的内置性质:

(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(def true-samples
["123"
"112233"
"13"])
(def false-samples
["10"
"12324"])
(defn char->int
[char-or-str]
(let [str-val (str char-or-str)] ; coerce any chars to len-1 strings
(assert (= 1 (count str-val)))
(Integer/parseInt str-val)))

(dotest
(is= 5 (char->int "5"))
(is= 5 (char->int 5))
(is= [1 2 3] (mapv char->int "123"))
; this shows what we are going for
(is (<= 1 1 2 2 3 3))
(isnt (<= 1 1 2 1 3 3))

现在测试字符序列:

;-----------------------------------------------------------------------------
; using built-in `<=` function
(doseq [true-samp true-samples]
(let [digit-vals (mapv char->int true-samp)]
(is (apply <= digit-vals))))
(doseq [false-samp false-samples]
(let [digit-vals (mapv char->int false-samp)]
(isnt (apply <= digit-vals))))

如果你想写自己的,你可以这样:

(defn increasing-equal-seq?
"Returns true iff sequence is non-decreasing"
[coll]
(when (< (count coll) 2)
(throw (ex-info "coll must have at least 2 vals" {:coll coll})))
(loop [prev      (first coll)
remaining (rest coll)]
(if (empty? remaining)
true
(let [curr           (first remaining)
prev-next      curr
remaining-next (rest remaining)]
(if (<= prev curr)
(recur prev-next remaining-next)
false)))))
;-----------------------------------------------------------------------------
; using home-grown loop/recur
(doseq [true-samp true-samples]
(let [digit-vals (mapv char->int true-samp)]
(is (increasing-equal-seq? digit-vals))))
(doseq [false-samp false-samples]
(let [digit-vals (mapv char->int false-samp)]
(isnt (increasing-equal-seq? digit-vals))))
)

有结果

-------------------------------
Clojure 1.10.1    Java 13
-------------------------------
Testing tst.demo.core
Ran 2 tests containing 15 assertions.
0 failures, 0 errors.
Passed all tests
Finished at 23:36:17.096 (run time: 0.028s)

looprecur一起使用。 假设您需要以下输入 v/s 输出 -

  • "543221" => 假
  • "54321" => 假
  • "12345" => 真
  • "123345" => 真

以下功能可以提供帮助

;; Assuming char-to-int is defined by you before as per the question
(defn digits-dont-decrease?
[strng]
(let [digits (map char-to-int (seq strng))]
(loop [;;the bindings in loop act as initial state
decreases true
i (- (count digits) 2)]
(let [decreases (and decreases (>= (nth digits (+ i 1)) (nth digits i)))]
(if (or (< i 1) (not decreases))
decreases
(recur decreases (dec i)))))))

这应该适用于任何长度的数字字符串。

希望这有帮助。如果您正在寻找其他:)的东西,请告诉我。

(defn non-decreasing? [str]
(every?
identity
(map
(fn [a b]
(<= (int a) (int b)))
(seq str)
(rest str))))
(defn non-decreasing-loop? [str]
(loop [a (seq str) b (rest str)]
(if-not (seq b)
true
(if (<= (int (first a)) (int (first b)))
(recur (rest a) (rest b))
false))))
(non-decreasing? "112334589")
(non-decreasing? "112324589")
(non-decreasing-loop? "112334589")
(non-decreasing-loop? "112324589")