2011-07-31 33 views
5

私はClojureには新しく、labreplからいくつかの基本的なことをやっています。例えば、elosska→elößkäのように、ある文字を他の文字に置き換える関数を書いてみたいと思います。mapsを使った反復処理

私はこれを書いた:

(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))) 

を私は期待するとして、それは動作しません。私を手伝ってくれますか?

答えて

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") 
+0

ええ、それは私より甘いです。非常に良い:-) – Scott

+0

はい、 'reduce'はより機能的で短く、私はちょうど問題がどこに発生するかを示したいと思っていました... –

+0

うわー、これをgrokに少しかかりました、それは還元と引数の破壊の巧妙な使い方です!私はこの技術を自分のコードの一部ですぐに使うことができました。本当にこのような機能的な「パターン」を持った本があったらいいですね。 – NielsK

6

2つの問題はここにあります:あなたがどんな結果にテキストの独立したコピーに

  • str/replace作品を取得することはできませんので

    1. doseqは生産、その評価によって作成されたリストの先頭を保存しません4種類の結果 - doseqforに置き換えると、これを確認できます。リストには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ä" 
    

    PS機能にdefを使用することもおすすめしません。最上位フォームに使用する方が良いです。

  • +1

    ハムザ・ヤーリカヤは、機能的なスタイルでソリューションを提供 - 'あなたは、中間結果を収集する必要がある場合にreduce'は非常に便利です... –

    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))) 
    

    regex (re-pattern...ラインは、単に場合は、読み取りにクリーン、かつ簡単だったでしょうこれは、#"ss|a|o|u"に評価

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

    を明示的な文字列として入力しましたが、私はドイツ語の文字の定義を1つだけ持つことをお勧めしました。ここで

    +0

    私はこれがあると言うだろう特にパフォーマンスが懸念されている場合は、行く方法。 'StringBuffer'を使用して単一の文字列を構築し、置換のマップ上で' loop'-ingまたは 'reduce'-ingを実行すると置換ごとに1つの新しい文字列が作成され、常に文字列全体に渡ります前の手順から。また、提示されたすべてのソリューション(正しい)は 'clojure.string/replace'を使用しています。これは、1つの呼び出しで操作全体を処理できる組み込み関数であるため、処理できるようにする必要があります。さらに、これは基本的に問題文のように読まれます。 +1。 –

    +0

    ところで、私は、上記のように、置き換えがパターンを導入することはないと仮定しています。これはここに当てはまりますが、もしそうでなければ、それはさらなる明確化を必要とする完全に異なる問題になるでしょう(例えば、全ての操作が冪等であることを意味しますか?そうでなければ、パターン/マップを使用してそれらを保持することはできますか?)。ちょっと脇に... :-) –

    +0

    @Michałご意見ありがとうございます。私はパフォーマンスの低下を意識していなかったので、今日は貴重なものを学んだことがあります(まだClojureにはたくさんのことが学びました!)。 – Scott

    関連する問題