Итерация по карте с помощью дозы - PullRequest
5 голосов
/ 31 июля 2011

Я новичок в 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 ]

16 голосов
/ 31 июля 2011

Вот мой дубль,


(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")
6 голосов
/ 31 июля 2011

Алекс, конечно, уже правильно ответил на вопрос относительно исходной проблемы, используя 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", что было бы чище и проще для чтения, если бы оно вводилось как явная строка, но я подумал, что лучше всего иметь только одно определение немецких букв.

6 голосов
/ 31 июля 2011

Здесь есть 2 проблемы:

  1. doseq не сохраняет заголовок списка, созданного его оценкой, поэтому вы не получите никаких результатов
  2. str/replace работает с отдельными копиями текста, давая 4 разных результата - вы можете проверить это, заменив doseq на for, и вы получите список с 4 записями.

Ваш код может быть переписан следующим образом:

(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 в функции - лучше использовать его для форм верхнего уровня

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...