使用doseq迭代地图

时间:2011-07-31 15:22:21

标签: clojure

我是Clojure的新手,我正在从labrepl做一些基本的东西,现在我想编写一个用其他字母替换某些字母的函数,例如:elosska→elößkä。

我写了这个:

(ns student.dialect (:require [clojure.string :as str]))
(defn germanize
  [sentence]
  (def german-letters {"a" "ä" "u" "ü" "o" "ö" "ss" "ß"})
  (doseq [[original-letter new-letter] german-letters]
    (str/replace sentence original-letter new-letter)))

但它没有像我期望的那样起作用。你能帮帮我吗?

3 个答案:

答案 0 :(得分:16)

这是我的看法,


(def german-letters {"a" "ä" "u" "ü" "o" "ö" "ss" "ß"})

(defn germanize [s]
  (reduce (fn[sentence [match replacement]]
            (str/replace sentence match replacement)) s german-letters))


(germanize "elosska")

答案 1 :(得分:6)

这里有两个问题:

  1. doseq不会保留由其评估创建的列表头部,因此您不会获得任何结果
  2. str/replace处理单独的文本副本,产生4种不同的结果 - 您可以将doseq替换为for来检查这一点,然后您将获得包含4个条目的列表。
  3. 您可以按照以下方式重写代码:

    (def german-letters {"a" "ä" "u" "ü" "o" "ö" "ss" "ß"})
    (defn germanize [sentence]
      (loop [text sentence
             letters german-letters]
        (if (empty? letters)
          text
          (let [[original-letter new-letter] (first letters)]
            (recur (str/replace text original-letter new-letter)
                   (rest letters))))))
    

    在这种情况下,会收集中间结果,因此所有替换都应用于相同的字符串,从而生成正确的字符串:

    user> (germanize "elosska")
    "elößkä"
    

    P.S。也不建议在函数中使用def - 最好将它用于顶级表单

答案 2 :(得分:6)

亚历克斯当然已经使用doseq正确回答了有关原始问题的问题......但我发现这个问题很有意思,并希望看到更具“功能性”的解决方案。我的意思是不使用循环。

我想出了这个:

(ns student.dialect (:require [clojure.string :as str]))

(defn germanize [sentence]
  (let [letters {"a" "ä" "u" "ü" "o" "ö" "ss" "ß"}
        regex (re-pattern (apply str (interpose \| (keys letters))))]
    (str/replace sentence regex letters)))

产生相同的结果:

student.dialect=> (germanize "elosska")
"elößkä"

regex (re-pattern...行简单地评估为#"ss|a|o|u",如果作为显式字符串输入,它本来更清晰,更易于阅读,但我认为最好只有一个德语定义字母。