web-dev-qa-db-fra.com

Comment puis-je convertir un Lazyseq de caractères à une chaîne de clojure?

Disons que j'ai un Lazeueq de Java.lang.Character comme

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

Comment puis-je convertir cela en une chaîne? J'ai essayé l'évidence

(String. my-char-seq)

mais ça jette

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

Je pense que parce que le constructeur de string s'attend à une primitive Char [] au lieu d'un LAZYSEQ. Alors j'ai essayé quelque chose comme

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

mais cela jette la même exception. Le problème est maintenant que dans le tablea renvoie a java.lang.character [] au lieu d'une primitive Char []. Ceci est frustrant, car je génère en fait ma séquence de caractère comme celle-ci

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

Fondamentalement, j'ai un SEQ d'INTS représentant ASCII caractères; 65 = A, etc. Vous pouvez voir que j'ai explicitement utiliser la fonction de coercition de type primitive (((char x).

Ce que cela signifie que ma fonction mon map renvoie une primitive char mais la fonction de clojure carte La fonction globalement renvoie le Java.lang .Character objet.

54
Robert Campbell

Cela marche:

(apply str my-char-seq)

Fondamentalement, STR appelle Tostring () sur chacun de ses arguments, puis les concaténe. Ici, nous utilisons Appliquer pour transmettre les caractères de la séquence en tant que arguments à STR.

106
Siddhartha Reddy

Une autre façon est d'utiliser clojure.string/join, comme suit:

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

Il y a une forme alternative de clojure.string/join qui accepte un séparateur. Voir:

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

Pour des problèmes plus compliqués, vous pouvez également souhaiter regarder strcatde la bibliothèque de Tupelo :

(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

Comme cas particulier, si le type sous-jacent de la séquence en question est clojure.lang.StringSeq vous pouvez aussi faire:

(.s (my-seq))

ce qui est extrêmement performant car il s'agit simplement de tirer le champ de charcutage final public de la classe Clojure StringSeq.

Exemple:

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

(.s (seq "foo"))
=> "foo"

(type (.s (seq "foo")))
=> Java.lang.String

un exemple des implications de synchronisation (et notez la différence lors de l'utilisation d'un indice de type):

(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