Подтвердить что ты не робот

Обратить строку (простой вопрос)

Есть ли лучший способ сделать это в Clojure?

daniel=> (reverse "Hello")
(\o \l \l \e \H)

daniel=> (apply str (vec (reverse "Hello")))
"olleH"

Вам нужно делать бит apply $ str $ vec каждый раз, когда вы хотите вернуть строку обратно в ее исходную форму?

4b9b3361

Ответ 1

Вам лучше использовать clojure.string/reverse:

user=> (require '[clojure.string :as s])
nil
user=> (s/reverse "Hello")
"olleH"

UPDATE: для любопытных здесь следуют фрагменты исходного кода для clojure.string/reverse как в Clojure (v1.4), так и в ClojureScript

; clojure:
(defn ^String reverse
  "Returns s with its characters reversed."
  {:added "1.2"}
  [^CharSequence s]
  (.toString (.reverse (StringBuilder. s))))

; clojurescript
(defn reverse
  "Returns s with its characters reversed."
  [s]
  (.. s (split "") (reverse) (join "")))

Ответ 2

ОК, поэтому было бы легко свернуть свою собственную функцию с использованием внутри или использовать специальную версию обратного, которая работает лучше (но только) в строках. Однако главное, о чем подумать, это арность (количество и тип параметров) функции str, а также тот факт, что обратное работает в коллекции.

(doc reverse)

clojure.core/reverse
([coll])
Returns a seq of the items in coll in reverse order. Not lazy.

Это означает, что reverse работает не только на строки, но и на всех других коллекциях. Однако, поскольку reverse ожидает коллекцию как параметр, он обрабатывает строку как набор символов

(reverse "Hello")

и возвращает его также

(\o \l \l \e \H)

Теперь, если мы просто заменим функции для коллекции, вы можете определить разницу:

(str '(\o \l \l \e \H) )
"(\\o \\l \\l \\e \\H)"

а

(str \o \l \l \e \H )
"olleH"

Большая разница между ними - это количество параметров. В первом примере str принимает один параметр, набор из 5 символов. Во втором str принимает 5 параметров: 5 символов.

Что ожидает функция str?

(doc str)
-------------------------
clojure.core/str
([] [x] [x & ys])
  With no args, returns the empty string. With one arg x, returns
  x.toString().  (str nil) returns the empty string. With more than
  one arg, returns the concatenation of the str values of the args.

Таким образом, когда вы указываете один параметр (коллекцию), все str возвращает значение toString коллекции. Но чтобы получить желаемый результат, вам нужно передать 5 символов в виде отдельных параметров на str, а не сама коллекция. Применить - это функция, которая используется, чтобы "попасть внутрь" коллекции и сделать это.

(apply str '(\o \l \l \e \H) )
"olleH"

Функции, которые обрабатывают несколько отдельных параметров, часто видны в Clojure, поэтому хорошо понимать, когда и зачем вам нужно применять. С другой стороны, чтобы понять, почему автор функции str заставил его принимать несколько параметров вместо коллекции? Обычно есть довольно веская причина. Какой распространенный вариант использования функции str? Не конкатенация набора отдельных символов, но конкатенация значений, строк и результатов функции.

(let [a 1 b 2]
  (str a "+" b "=" (+ a b)))
"1+2=3"

Что делать, если у нас была str, которая принимала в качестве параметра одну коллекцию?

(defn str2
  [seq]
  (apply str seq)
  )

(str2 (reverse "Hello"))
"olleH"

Прохладный, он работает! Но теперь:

(let [a 1 b 2]
  (str2 '(a "+" b "=" (+ a b)))
  )
"a+b=(+ a b)"

Хммм, теперь как это решить?:)

В этом случае, заставляя str принимать несколько параметров, которые оцениваются до выполнения функции str, дает str самый простой синтаксис. Всякий раз, когда вам нужно использовать str в коллекции, примените простой способ преобразования коллекции в отдельные параметры.

Создание str, которое принимает коллекцию и оценивать каждую часть внутри, потребовало бы больше усилий, помогало бы только в менее распространенных случаях использования, приводило бы к более сложному коду или синтаксису или ограничивало бы его применимость. Таким образом, может быть лучший способ перевернуть строки, но наоборот, применить и str лучше всего в том, что они делают.

Ответ 3

Применить, как и обратное, работает с любым типом типа, а не только с векторами, поэтому

(применить str (reverse "Hello" ))

немного короче. clojure.string/reverse должен быть более эффективным.