当我在 Clojure 中映射列表时,如何将它与其他文本穿插在一起?

When I map a list in Clojure, how can I intersperse it with other text?

假设我有一个像

这样的列表
(def nodes ["a", "b", "c"])

我想将 nodes 转换为以下字符串:

a -> b -> c

怎么办?

(apply str (mapcat
             (fn [node]
               (str node " -> ")
               )
             nodes
             )
       )

结果

"a -> b -> c -> "

我现在可以检查结果字符串是否以 -> 结尾,如果是,删除最后一个 ->.

但这看起来不是很优雅。在 Clojure 中执行此操作的正确方法是什么?

更新 1:

(transduce
  (fn [rf]
    (fn
      ([] "")
      ([result] result)
      ([result input] (str
                        result
                        "->"
                        input))
      )
    )
   cat
   ""
   nodes
  )

结果

"->a->b->c"

(def nodes ["a" "b" "c"])

(clojure.string/join " -> " nodes) ;; => "a -> b -> c"

除了clojure.string/join之外,如果您愿意,您还可以使用reduce制作自己的join

(second (reduce #(vector nil (str (second %1)
                                  (if (= :begin (first %1))
                                    ""
                                    " -> ")
                                  %2))
                [:begin ""]
                ["a" "b" "c"]))

减少:https://clojuredocs.org/clojure_core/clojure.core/reduce

clojure.string/join 答案完全符合您的特定需求。

但是,为了更通用的解决方案,clojure.core/interpose 从插入另一个序列元素之间的固定项创建序列。

(def nodes ["a" "b" "c"])
(interpose " -> " nodes)
;; => ("a" " -> " "b" " -> " "c")
(apply str (interpose " -> " nodes))
;; => "a -> b -> c"

值得注意的是,这大约需要 3 倍的时间,因此请确保您需要通用性!

(use 'criterium.core)
(quick-bench (clojure.string/join " -> " nodes))
;; => Execution time mean : 299.877733 ns
(quick-bench (apply str (interpose " -> " nodes)))
;; => Execution time mean : 950.765805 ns