2

4clojure.orgで設定された問題を解決しようとしています。私は23番です(「逆」関数を使用せずに文字列を逆にします)。このエラーが発生します:

java.lang.LongからISeqを作成する方法がわからない

これが私のコードです:

(fn rev [coll] 
  (if (= () coll)
    nil
    ((cons(rev (rest coll))(first coll)))))

これに編集されました:

(fn rev [coll] 
  (if (empty? coll)
    coll
    (concat(rev (rest coll))((list first coll)))))

おそらくこれは、シーケンスの先頭をシーケンスの残りの部分の終わりに変換しようとすることによるものです。

これを行う正しい方法は何ですか?

4

3 に答える 3

3

consin clojureの2番目の引数はシーケンスである必要がありますが、シーケンスで(first coll)はなくコレクションの要素です。おそらくあなたは数字のコレクションを渡すので(first coll)、数字(長い)を吐き出し、clojureはISeqその数字から作成することはできません。

user=> (doc cons)
-------------------------
clojure.core/cons
([x seq])
  Returns a new seq where x is the first element and seq is
    the rest.

次のように、reverseを簡単に実装できます。

(fn rev [coll]
    (reduce conj () coll))

上記のコードを確認すると、4clojureサイトの3つのテストケースすべてに合格しました。

于 2013-02-18T01:53:59.850 に答える
3

このエラーは、要素を。にではなく、要素にしようとしconsているためです。言い換えれば、あなたの議論は間違った順序になっています。ただし、順序を修正すると、リストを同じ順序でつなぎ合わせるだけになります。seqseqcons

あなたが持っているのと同じ一般的な考えを使用して、2番目の引数をリストにまとめてから2つのリストを一緒にまとめることで(list ...)、 2番目の引数をリストに変えることができます。concat

(fn rev [coll] 
  (if (empty? coll)
    coll
    (concat
      (rev (rest coll))
      (list (first coll)))))

進むにつれて、より簡潔な解決策を見つけることができます。

于 2013-02-18T01:57:56.043 に答える
1

OPのように、when-letand ifnextandlastなどを使用して再帰的なソリューションを構築しようとするとイライラします。そこで、@ ntalbsの回答を理解し、これをさらに進めることができるかどうかを確認しようとしています。 //clojuredocs.org/quickref/Clojure%20Core

パート#1-オブザベーション:
consはリストの関数ですが、conjはコレクションの総称関数でありconcat、シーケンスの「Use(modification)」の下にリストされていますが、レイジーシーケンスを返します。では、これらのことは実際にはどのように異なりますか?

  1. 引数の順序が重要です。値とシーケンスは使用できませんconj。シーケンスと値のみを使用できます。それconsは逆です。concatより寛容なようです。

    user=> (type (conj 1 '(2 3 4 5)))
    ClassCastException java.lang.Long cannot be cast to clojure.lang.IPersistentCollection  clojure.core/conj (core.clj:83)
    user=> (type (cons '(2 3 4 5) 1))
    IllegalArgumentException Don't know how to create ISeq from: java.lang.Long  clojure.lang.RT.seqFrom (RT.java:505)
    
  2. 3つの異なるリターンタイプ:Cons、PersistentList、またはLazySeq

    user=> (type (cons 1 '(2 3 4 5)))
    clojure.lang.Cons
    user=> (type (conj '(2 3 4 5) 1))
    clojure.lang.PersistentList
    user=> (type (concat 1 '(2 3 4 5)))
    clojure.lang.LazySeq
    
  3. コレクションの種類ごとに異なる動作:

    user=> (cons 3 (sorted-set 5 7 2 7))
    (3 2 5 7)     ; type = Cons, 3 is just appended to the list, 
    user=> (conj (sorted-set 5 7 2 7) 3)
    #{2 3 5 7}    ; type = PersistentTreeSet, with 3 in the correct position.
    user=> (concat 3 (sorted-set 5 7 2 7))   ; LazySeq can't be directly returned, so...(order doesn't matter)
    IllegalArgumentException Don't know how to create ISeq from: java.lang.Long  clojure.lang.RT.seqFrom (RT.java:505)
    

私の考えでconjは、最も単純な動作をしているので、実際に怠惰なシーケンスまたは具体的にリストが必要な場合を除いて、これを優先的に使用します。

パート#2- @Ramyの「私には密度が高すぎる」@ntalbsのソリューションを理解する。

上記の説明conjは、それがコレクションに物事を追加するための最も適切な方法であることを示唆しています。これはまさに@ntalbsのソリューションが行うことです。の使用法reducehttp://clojuredocs.org/clojure_core/clojure.core/reduce にあります。これは、コレクション内の値をまとめながら関数を適用する効果的な方法です。

(reduce f val coll)

したがって、コレクションの各メンバーにreduce適用されます。したがって、呼び出しはコレクションを取得し、最初に適用されます。次に、、、などを適用します。ここで、は前の手順の結果です。fval(reduce conj () coll)(conj () (first coll))(conj result (second coll))(conj result (third coll))result

reduce非常に強力なコマンドのように見えます。

パート3-さらに別の解決策

(fn rev [coll]
    (into () coll))

ドキュメントから、のinto構文糖衣であるように見えます(reduce conj to-coll from-coll)。これがエレガントなのか、それとも単に密集しているのかはわかりません。ただし、最小限のキーストロークで機能します。

于 2013-11-14T20:00:37.280 に答える