【问题标题】:How can I convert a LazySeq of Characters to a String in Clojure?如何在 Clojure 中将字符的 LazySeq 转换为字符串?
【发布时间】:2010-12-13 20:30:24
【问题描述】:

假设我有一个 java.lang.Character 之类的 LazySeq

(\b \ \! \/ \b \ \% \1 \9 \/ \. \i \% \$ \i \space \^@)

如何将其转换为字符串?我已经尝试了明显的

(String. my-char-seq)

但它会抛出

java.lang.IllegalArgumentException: No matching ctor found for class java.lang.String (NO_SOURCE_FILE:0)
[Thrown class clojure.lang.Compiler$CompilerException]

我认为是因为 String 构造函数需要原始 char[] 而不是 LazySeq。所以我尝试了类似的东西

(String. (into-array my-char-seq))

但它会引发相同的异常。现在的问题是 into-array 返回的是 java.lang.Character[] 而不是原始的 char[]。这很令人沮丧,因为我实际上是这样生成我的字符序列的

(map #(char (Integer. %)) seq-of-ascii-ints)

基本上我有一个表示 ASCII 字符的整数序列; 65 = A 等。你可以看到我明确地使用了原始类型强制函数(char x)

这意味着我的 ma​​p 函数返回一个原始 char 但 Clojure ma​​p 函数整体返回 java .lang.Character 对象。

【问题讨论】:

    标签: map clojure types primitive-types coercion


    【解决方案1】:

    这行得通:

    (apply str my-char-seq)
    

    基本上,str 在其每个参数上调用 toString(),然后将它们连接起来。这里我们使用 apply 将序列中的字符作为 args 传递给 str

    【讨论】:

      【解决方案2】:

      另一种方式是使用clojure.string/join,如下:

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

      clojure.string/join 有另一种形式,它接受分隔符。见:

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

      对于更复杂的问题,你也不妨看看strcatfrom the Tupelo library

      (require '[tupelo.core :as t] )
      (prn (t/strcat "I " [ \h \a nil \v [\e \space (byte-array [97])
                        [ nil 32 "complicated" (Math/pow 2 5) '( "str" nil "ing") ]]] ))
      ;=> "I have a complicated string"
      

      【讨论】:

        【解决方案3】:

        作为一种特殊情况,如果相关序列的基础类型是clojure.lang.StringSeq,您也可以这样做:

        (.s (my-seq))
        

        这是非常高效的,因为它只是从 clojure StringSeq 类中提取公共的最终 CharSequence 字段。

        例子:

        (type (seq "foo"))
        => clojure.lang.StringSeq
        
        (.s (seq "foo"))
        => "foo"
        
        (type (.s (seq "foo")))
        => java.lang.String
        

        时间含义的示例(并注意使用类型提示时的区别):

        (time 
          (let [q (seq "xxxxxxxxxxxxxxxxxxxx")]
            (dotimes [_ 1000000]
              (apply str q))))
        "Elapsed time: 620.943971 msecs"
        => nil
        
        (time 
          (let [q (seq "xxxxxxxxxxxxxxxxxxxx")]
            (dotimes [_ 1000000]
              (.s q))))
        "Elapsed time: 1232.119319 msecs"
        => nil
        
        (time 
          (let [^StringSeq q (seq "xxxxxxxxxxxxxxxxxxxx")]
            (dotimes [_ 1000000]
              (.s q))))
        "Elapsed time: 3.339613 msecs"
        => nil
        

        【讨论】:

          猜你喜欢
          • 2011-08-03
          • 2011-04-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多