从字符序列中创建字符串

时间:2011-09-05 07:15:31

标签: string clojure state 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))))))

谢谢!

3 个答案:

答案 0 :(得分:12)

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

正确的方法是:

(apply str seq)

例如,

 user=> (apply str [\1 \2 \3 \4])
 "1234"

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

答案 1 :(得分: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))))))

当然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)))

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

(defn make-str-from-chars
  "make a string from a sequence of characters"
  [chars]
  (reduce str "" chars))

这已经很好而且简短,但在这种特殊情况下,我们可以使用apply做得更好。然后str可以使用基础StringBuilder来充分发挥其力量。

(defn make-str-from-chars
  "make a string from a sequence of characters"
  [chars]
  (apply str chars))

希望这有帮助。

答案 2 :(得分:2)

您还可以使用 clojure.string / join ,如下所示:

(require '[clojure.string :as str] )
(assert (= (vec "abcd")                [\a \b \c \d] ))
(assert (= (str/join  (vec "abcd"))    "abcd" ))

还有一种替代形式的 clojure.string / join ,它接受一个分隔符。参见:

http://clojuredocs.org/clojure_core/clojure.string/join