我有这段clojure
代码:
(def up (memfn toUpperCase))
(str "\n" (apply str (interpose "\n" (map up '("one" "two")))) "\n"); "\nONE\nTWO\n"
代码完全按照预期的方式执行:获取字符串列表,每个字符串大写,并用\n
(inc之前和之后)包围每个字符串。
但必须有一种方法可以用更强大的优雅方式来编写它。请帮忙。
答案 0 :(得分:4)
你可以组合地图和设置:
(apply str "\n" (map #(str (up %) "\n") '("one" "two")))
同样,不一定更优雅,有点在timtowdi的精神:
(clojure.pprint/cl-format false "~%~{~:@(~A~)~%~}" '("one" "two"))
有关cl格式字符串的教程,请参阅practical common lisp。
答案 1 :(得分:4)
我实际上非常喜欢这种事情的with-out-str
方法:
(with-out-str
(println)
(doseq [s ["one" "two"]]
(println (.toUpperCase ^String s))))
它看起来比你的原始方法慢2-3倍,并且马丁的“组合地图和设置”变体添加了类型提示(比cl-format
快〜30倍,但是明显胜过冷静因素: - ))。 (有关暗示和反思的说明,请参阅本答案的结尾。)
另一个版本只是为了保持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
更频繁地使用 ,即使没有指定类型提示。)
答案 2 :(得分:1)
我想出了:
(defn interpose-envelop-and-stringify [coll sep]
(str sep
(join sep coll)
sep))
(interpose-envelop-and-stringify (map up ["one" "two"]) "\n")
我正在使用clojure.string中的join
。
答案 3 :(得分:0)
你做对了。 一个建议 - 使用函数arg或let form来定义分隔符,在这种情况下,当你需要更改分隔符时,你只需要在一个地方改变它(不像你的情况那样是3)
(defn stringify [sq sep]
(reduce str sep (map #(str (.toUpperCase %) sep) sq)))
(stringify ["one" "two"] "\n") => "\nONE\nTWO\n"
答案 4 :(得分:0)
画眉操作可以使事情相当干净,但是仍然需要将列表加入一个大字符串所需的封闭应用。
(defn stringify [s] (apply str "\n" (map #(-> % .toUpperCase (str "\n")) s)))
(stringify '("one" "two")) ; yields "\nONE\nTWO\n"