Как я могу преобразовать LazySeq символов в строку в Clojure?

Допустим, у меня есть LazySeq из java.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]

Я думаю, потому что конструктор 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).

Это означает, что моя функция map возвращает примитивный char, а функция Clojure map в целом возвращает java.lang. Символьный объект.


person Robert Campbell    schedule 06.11.2009    source источник


Ответы (3)


Это работает:

(apply str my-char-seq)

По сути, str вызывает toString() для каждого из своих аргументов, а затем объединяет их. Здесь мы используем apply для передачи символов последовательности в качестве аргументов в str.

person Siddhartha Reddy    schedule 06.11.2009

Другой способ — использовать 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

Для более сложных задач вы также можете посмотреть strcat из библиотеки 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"
person Alan Thompson    schedule 01.02.2014

В качестве особого случая, если базовым типом рассматриваемой последовательности является clojure.lang.StringSeq, вы также можете сделать:

(.s (my-seq))

который чрезвычайно эффективен, поскольку он просто извлекает общедоступное конечное поле CharSequence из класса StringSeq clojure.

Пример:

(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
person Matias Bjarland    schedule 26.04.2017