webdevqa.jp.net

LajuSeqの文字をClojureで文字列に変換するにはどうすればよいですか?

LazySeq ofJava.lang.Characterのようなものがあるとしましょう

(\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]

文字列コンストラクターはLazySeqではなくプリミティブchar []を期待しているためだと思います。それで私は何かを試しました

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

ただし、同じ例外がスローされます。今問題はinto-arrayがプリミティブchar []ではなくJava.lang.Character []を返すことです。私は実際にこのように自分のキャラクターシーケンスを生成するので、これはイライラします

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

基本的に私はASCII文字; 65 = Aなど)を表すintのシーケンスを持っています。プリミティブ型強制関数(char x)を明示的に使用していることがわかります。

つまり、私のmap関数はプリミティブcharを返しますが、Clojure map関数は全体的にJava.lang.Characterオブジェクト。

54
Robert Campbell

これは機能します:

(apply str my-char-seq)

基本的に、strは、その各引数に対してtoString()を呼び出してから、それらを連結します。ここではapplyを使用して、シーケンス内の文字を引数としてstrに渡します。

106

別の方法は、次のように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

より複雑な問題については、strcatTupeloライブラリから を調べることもできます。

(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"
11
Alan Thompson

特殊なケースとして、問題のシーケンスの基になるタイプがclojure.lang.StringSeq次のこともできます:

(.s (my-seq))

これは、clojureのStringSeqクラスからpublic final 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
6
Matias Bjarland