2016-12-02 9 views
0

与えられた文字列の母音と子音の数を数える関数を作成しようとしています。戻り値は、vowelsconsonantsの2つのキーを持つマップです。それぞれのキーの値は単なるカウントです。私がこれまでに開発することができましたClojure forループが更新された値の原子を返さない

機能は、しかし

(defn count-vowels-consenants [s] 
    (let [m (atom {"vowels" 0 "consenants" 0}) 
     v #{"a" "e" "i" "o" "u"}] 
    (for [xs s] 
     (if 
      (contains? v (str xs)) 
      (swap! m update-in ["vowels"] inc) 
      (swap! m update-in ["consenants"] inc) 
     )) 
    @m)) 

(count-vowels-consenants "sldkfjlskjwe")戻って私が間違っているのは何{"vowels":0 "consenants": 0}

のですか?

EDIT:strからsに変更されました。strはClojureの関数です。

+1

アトムを更新する要件はありますか? – jmargolisvt

+0

@jmargolisvtいいえ、原子の具体的な要件はありません。私はClojureと状態を突き合わせる自然な方法だと思われましたが、私は選択肢を完全に開いています。 – idclark

+0

あなたは既にあなたの質問への回答を得ていますが、ここではおそらく今実現していると思われる根本的な誤解を強調したいと思います - クローズには "for loop"はありません。 'for'はリストを作成するために使われる[list comprehension](https://en.wikipedia.org/wiki/List_comprehension)のコンストラクトです。そのため、ループしません('ループが適切に命名される)。ループの文脈で「for」という言葉を特徴とする命令的言語からの混乱を招くことがありますが、これはクロージャーの意味ではありません。 – Josh

答えて

3

私はforが怠け者だと思うので、あなたが実際にそれを実現しようとするまでは何もしません。私はリストを実現したforループにfirstを追加し、str関数をstr文字列で上書きしてエラーを発生させました。理想的には、原子rigmaroleなしでこれを行うだけです。原子はあなたが望むものである場合

(defn count-vowels-consonants [s] 
    (let [v #{\a \e \i \o \u} 
     vowels (filter v s) 
     consonants (remove v s)] 
    {:consonants (count consonants) 
    :vowels (count vowels)})) 

、その代わりにfordoseqを使用して、それは、文字列内のすべてのための原子を更新します。また、関数バインディングでstr関数を使用して上書きしないように注意してください。

+1

FYI、 'group-by'はおそらく文字列/ seqに対して1回の反復しか行わないので、より良いでしょう。 – ClojureMostly

+0

@Brandon H ahhhh、 'str'でうまくキャッチする、それは本当に私のところではうんざりです。 – idclark

+0

これは私のソリューションよりもはるかにエレガントです。 'doseq'を私に指摘してくれてありがとう。 – idclark

1

は、@Brandon Hのように怠け者です。必要に応じて、ループ繰り返しを使用できます。ここで私はforループを繰り返す。

(defn count-vowels-consenants [input] 
    (let [m (atom {"vowels" 0 "consenants" 0}) 
     v #{"a" "e" "i" "o" "u"}] 
    (loop [s input] 
     (when (> (count s) 0) 
     (if 
      (contains? v (first (str s))) 
      (swap! m update-in ["vowels"] inc) 
      (swap! m update-in ["consenants"] inc) 
     )) 
     (recur (apply str (rest s)))) 
    @m)) 
1

スキームをもたらす。この辺が避けられない場合(スメ教育の理由で、私が思う)だけの方法でfor (の熱心同等に影響を与える側であるdoseqforを置き換える:あなたの初期に誤りがありますコード:strを入力パラメータとして使用し、それを関数として使用しようとしているので、clojure.coreからdefをシャドーイングします。

(defn count-vowels-consenants [input] 
    (let [m (atom {"vowels" 0 "consenants" 0}) 
     v #{"a" "e" "i" "o" "u"}] 
    (doseq [s input] 
     (if (contains? v (str s)) 
     (swap! m update-in ["vowels"] inc) 
     (swap! m update-in ["consenants"] inc))) 
    @m)) 
#'user/count-vowels-consenants 

user> (count-vowels-consenants "asdfg") 
;; {"vowels" 1, "consenants" 4} 

そうでなければ、次のようなことができますこの:

user> (reduce #(update %1 
         (if (#{\a \e \i \o \u} %2) 
         "vowels" "consonants") 
         (fnil inc 0)) 
       {} "qwertyui") 
;;{"consonants" 5, "vowels" 3} 

または

user> (frequencies (map #(if (#{\a \e \i \o \u} %) 
          "vowels" "consonants") 
         "qwertyui")) 
;;{"consonants" 5, "vowels" 3} 

またはこれ(あなたが良いなら代わりに "母音/子音" のtrue/falseを有する):

user> (frequencies (map (comp some? #{\a \e \i \o \u}) "qwertyui")) 
;;{false 5, true 3} 
+0

私はこれからいくつかのことを学んだ、ありがとう! – idclark

0

質問、およびすべての現存答えは、すべての文字が母音または子音であると仮定します。そうではありません。 ASCIIでさえ、大文字と小文字があります。私は次のようにします。

(defn count-vowels-consonants [s] 
    (let [vowels #{\a \e \i \o \u 
        \A \E \I \O \U} 
     classify (fn [c] 
        (if (Character/isLetter c) 
        (if (vowels c) :vowel :consonant)))] 
    (map-v count (dissoc (group-by classify s) nil)))) 

...例えば

(defn map-v [f m] (reduce (fn [a [k v]] (assoc a k (f v))) {} m)) 

(count-vowels-consonants "s2a Boo!") 
;{:vowel 3, :consonant 2} 

これは一度だけ文字列を横断:map-vmapのマップの値が関数です。

関連する問題