从字符序列中创建字符串

5 string state clojure sequence

此代码无法正常工作.你能解释一下原因吗?

(defn make-str [s c]
    (let [my-str (ref s)]
    (dosync (alter my-str str c))))

(defn make-str-from-chars
    "make a string from a sequence of characters"
    ([chars] make-str-from-chars chars "")
    ([chars result]
        (if (== (count chars) 0) result
        (recur (drop 1 chars) (make-str result (take 1 chars))))))
Run Code Online (Sandbox Code Playgroud)

谢谢!

Ale*_*Ott 12

这是从seq of characters创建字符串的非常慢且不正确的方法.主要问题是,更改不会传播 - ref会创建对现有字符串的新引用,但在从函数退出后,引用将被销毁.

正确的方法是:

(apply str seq)
Run Code Online (Sandbox Code Playgroud)

例如,

 user=> (apply str [\1 \2 \3 \4])
 "1234"
Run Code Online (Sandbox Code Playgroud)

如果你想让它更有效,那么你可以使用Java的StringBuilder来收集字符串中的所有数据.(Java中的字符串也是不可变的)


kot*_*rak 11

您将其中包含一个字符的序列传递给您的make-str函数,而不是字符本身.使用first而不是take应该给你想要的效果.

也没有必要使用参考.实际上,你对它们的使用是对它们的严重滥用.您已在函数中使用累加器,因此可以str直接使用.

(defn make-str-from-chars
  "make a string from a sequence of characters"
  ([chars] (make-str-from-chars chars ""))
  ([chars result]
    (if (zero? (count chars))
      result
      (recur (drop 1 chars) (str result (first chars))))))
Run Code Online (Sandbox Code Playgroud)

当然,count在这种情况下并不是很好,因为它总是需要遍历整个序列来计算它的长度.因此,您不必要地多次遍历输入序列.通常用于seq识别序列何时耗尽.我们也可以使用next而不是drop节省创建不必要的序列对象的一些开销.请务必捕获返回值,seq以避免以后对象创建的开销.我们这样做if-let.

(defn make-str-from-chars
  "make a string from a sequence of characters"
  ([chars] (make-str-from-chars chars ""))
  ([chars result]
     (if-let [chars (seq chars)]
       (recur (next chars) (str result (first chars)))
       result)))
Run Code Online (Sandbox Code Playgroud)

像这样的函数,它只是在完全消耗它的输入时返回累加器,为之哭泣reduce.

(defn make-str-from-chars
  "make a string from a sequence of characters"
  [chars]
  (reduce str "" chars))
Run Code Online (Sandbox Code Playgroud)

这已经很好而且简短,但在这种特殊情况下,我们可以通过使用来做得更好apply.然后str可以使用底层StringBuilder的全部功率.

(defn make-str-from-chars
  "make a string from a sequence of characters"
  [chars]
  (apply str chars))
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.