在clojure中,map和stringify:使其更简单

时间:2012-02-14 21:45:11

标签: clojure lisp

map和stringify

我有这段clojure代码:

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

代码完全按照预期的方式执行:获取字符串列表,每个字符串大写,并用\n(inc之前和之后)包围每个字符串。

但必须有一种方法可以用更强大的优雅方式来编写它。请帮忙。

5 个答案:

答案 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"