web-dev-qa-db-ja.com

コレクションの末尾に要素を配置します

私は自分が多くのことをしていることに気づきました:

(concat coll [e])ここで、colはコレクションであり、eは単一の要素です。

Clojureでこれを行う機能はありますか? conjがベクターに最も適していることは知っていますが、どのcollが使用されるかは事前にはわかりません。たとえば、ベクター、リスト、またはソートされたセットです。

51
Michiel Borkent

concatは、コレクションの末尾に要素を追加したり、2つのコレクションを連結したりしません。

concatは、他の2つのseqを連結したseqを返します。シーケンスの推論元のコレクションの元のタイプは、concatの戻りタイプでは失われます。

現在、clojureコレクションには、効率的なコードを記述するために知っておく必要のあるさまざまなプロパティがあります。そのため、コアであらゆる種類のコレクションを連結するユニバーサル関数はありません。それどころか、リストとベクターにはconjが知っている「自然な挿入位置」があり、コレクションの種類に合ったものを実行します。

14
Laurent Petit

これは、あらゆる種類のコレクションの末尾に常に追加する関数に対するOPの要求に対処するための@amalloyの回答に対する非常に小さな補遺です。これは(concat coll [x])の代替です。元のコレクションのベクターバージョンを作成するだけです。

(defn conj*
  [s x]
  (conj (vec s) x))

警告:

レイジーシーケンスから始めた場合、レイジーを破壊しました。出力はレイジーではありません。これは、ニーズに応じて、良いことも悪いこともあります。

ベクトルの作成にはいくらかコストがかかります。この関数を頻繁に呼び出す必要があり、(たとえば、Criteriumでのベンチマークによって)このコストが目的にとって重要であることがわかった場合は、他の回答のアドバイスに従って、最初にベクトルを使用してみてください。

6
Mars

AmalloyとLaurent Petitがすでに言ったことの最高のものを抽出するには:conj関数を使用

Clojureが提供する優れた抽象化の1つは、conj関数を含むSequence APIです。可能な限り、コードは可能な限りコレクション型に依存しないようにし、代わりにseq APIを使用してコレクションの操作を処理し、特定する必要がある場合にのみ特定のコレクション型を選択します。

ベクトルが一致する場合、はい、conjは最後にアイテムを追加します。代わりにリストを使用する場合、conjはコレクションの先頭に物を追加します。しかし、標準のseq API関数を使用してコレクションの「トップ」(ベクターの後ろ、リストの前)からアイテムをプルする場合、どの実装を使用するかは問題になりません。最高のパフォーマンスを実現するため、アイテムの追加と削除が一貫します。

5
semperos