В clojure, map и stringify: сделать это проще - PullRequest
0 голосов
/ 15 февраля 2012

отобразить и преобразовать в строку

У меня есть этот кусок clojure код:

(def up (memfn toUpperCase))   
(str "\n" (apply str (interpose "\n" (map up '("one" "two")))) "\n"); "\nONE\nTWO\n"

Код делает именно то, что должен: взять список строк, каждый из них в верхнем регистре и заключить в каждый из них \n (включая до и после).

Но должен быть способ написать это более элегантным способом. Пожалуйста, помогите.

Ответы [ 5 ]

4 голосов
/ 15 февраля 2012

Мне действительно нравится with-out-str подход к такого рода вещам:

(with-out-str
  (println)
  (doseq [s ["one" "two"]]
    (println (.toUpperCase ^String s))))

Кажется, он примерно в 2-3 раза медленнее, чем ваш оригинальный подход и вариант "комбинированной карты и вставки" Мартина сдобавлены подсказки типа (и ~ в 30 раз быстрее, чем cl-format, что, однако, явно выигрывает в коэффициенте крутизны :-)).(См. В конце этого ответа примечание о намеках и размышлениях.)

Еще одна версия, призванная поддерживать дух timtowtdi: для максимальной скорости (до ~ 2-кратного ускорения по сравнению с исходной версией), если ваместь причина позаботиться об этом, вы можете использовать

(loop [sb (doto (StringBuilder.)
            (.append \newline))
       strs ["one" "two"]]
  (if-let [s (first strs)]
    (do (.append sb (.toUpperCase ^String s))
        (.append sb \newline)
        (recur sb (next strs)))
    (.toString sb)))))

Несколько касательно основного вопроса, я рассчитал все подходы после того, как избавился от всех предупреждений об отражении;в частности, я использовал

(def up #(.toUpperCase ^String %))

(кстати, #(.foo %), кажется, используется намного чаще, чем memfn, даже когда подсказки типов не указаны.)

4 голосов
/ 15 февраля 2012

Вы можете объединить карту и вставить:

(apply str "\n" (map #(str (up %) "\n") '("one" "two")))

также, не обязательно более элегантно, немного в духе timtowdi:

(clojure.pprint/cl-format false "~%~{~:@(~A~)~%~}" '("one" "two"))

см. практический общий шрифт для учебника по строкам формата cl.

1 голос
/ 15 февраля 2012

Я придумал:

 (defn interpose-envelop-and-stringify [coll sep]
   (str sep
        (join sep coll)
        sep))
 (interpose-envelop-and-stringify (map up ["one" "two"]) "\n")

Я использую join из clojure.string .

0 голосов
/ 22 февраля 2012

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

(defn stringify [s] (apply str "\n" (map #(-> % .toUpperCase (str "\n")) s)))

(stringify '("one" "two")) ; yields "\nONE\nTWO\n"
0 голосов
/ 15 февраля 2012

Вы делаете правильные вещи.Один совет - используйте функцию arg или let форму для определения разделителя, в том случае, когда вам нужно изменить разделитель, вы меняете его только в одном месте (не 3, как в вашем случае)

(defn stringify [sq sep]
  (reduce str sep (map #(str (.toUpperCase %) sep) sq)))

(stringify ["one" "two"] "\n") => "\nONE\nTWO\n"
...