user=> (map (fn [x] (.toUpperCase x)) (.split "Dasher Dancer Prancer" " "))
("DASHER" "DANCER" "PRANCER")
Clojureには豊富なデータ構造があります。それらは共通の特性を共有しています。
不変です。
読み取り可能です。
equalsの実装において、適切な値の等価性セマンティクスをサポートしています。
良好なハッシュ値を提供します。
さらに、コレクションは
インターフェースを介して操作されます。
シーケンスをサポートします。
永続的な操作をサポートします。
メタデータのサポート
java.lang.Iterableを実装
java.util.Collectionまたはjava.util.Mapのオプションではない(読み取り専用)部分を具現化
nilはClojureの任意のデータ型の可能な値です。nilはJavaのnullと同じ値です。Clojureの条件式システムはnilとfalseに基づいており、nilとfalseは条件テストにおける論理的な偽の値を表します - それ以外のものは論理的な真です。さらに、nilはシーケンスプロトコルにおけるシーケンスの終端を示すセマンティクス値として使用されます。
ClojureはデフォルトでJVMプリミティブ値を完全にサポートしており、数値アプリケーションのための高性能で慣習的なClojureコードを可能にします。
Clojureはまた、java.lang.Numberから派生したJavaのボックス化された数値型(BigIntegerとBigDecimalを含む)に加えて、独自のRatio型もサポートしています。いくつかの特別な処理があります。
デフォルトでは、Clojureは自然数をJavaのlongプリミティブ型インスタンスとして扱います。プリミティブ整数演算の結果がプリミティブ値に収まりきらないほど大きい場合、java.lang.ArithmeticExceptionがスローされます。Clojureは、アポストロフィが付いた一連の代替数学演算子を提供します:+'、-'、*'、inc'、dec'。これらの演算子はオーバーフロー時にBigIntに自動的に昇格しますが、通常の数学演算子よりも効率が低くなります。
Clojureの文字列はJavaのStringです。出力も参照してください。
user=> (map (fn [x] (.toUpperCase x)) (.split "Dasher Dancer Prancer" " "))
("DASHER" "DANCER" "PRANCER")
シンボルは、通常は何か他のものを参照するために使用される識別子です。プログラム形式で使用して、関数パラメータ、letバインディング、クラス名、グローバル変数を参照できます。名前とオプションの名前空間を持ち、どちらも文字列です。シンボルにはメタデータを含めることができます(with-metaを参照)。
キーワードと同様に、シンボルは1つの引数(マップ)とオプションの2番目の引数(デフォルト値)のinvoke()に対してIFnを実装しています。たとえば、('mysym my-hash-map :none)
は(get my-hash-map 'mysym :none)
と同じ意味です。getを参照してください。
Clojureのコレクションはすべて不変であり、永続的です。特に、Clojureのコレクションは、構造共有を利用することで、「変更された」バージョンの効率的な作成をサポートし、永続的な使用に関するすべての性能に関する保証を行います。コレクションは効率的で、本質的にスレッドセーフです。コレクションは抽象化によって表され、1つ以上の具体的な実現方法がある場合があります。「変更」操作は新しいコレクションを生成するため、新しいコレクションはソースコレクションと同じ具体的な型ではない可能性がありますが、同じ論理的な(インターフェース)型になります。
全ての集合は、集合のサイズを取得するためのcount、集合に「追加」するためのconj、そして集合全体を走査できるシーケンスを取得するためのseqをサポートしています。ただし、それらの具体的な動作は、集合の種類によってわずかに異なります。
Clojureは、集合(およびその他の型)に対してより優れたハッシュ特性を提供する独自のハッシュ計算を提供しており、hasheq値として知られています。
IHashEq
インターフェースは、hasheq値を取得するためのhasheq()
関数を提供する集合をマークします。Clojureでは、hash関数を用いてhasheq値を計算できます。
順序付き集合(ベクター、リスト、シーケンスなど)は、hasheqの計算に以下のアルゴリズムを使用する必要があります(hashはhasheqを計算します)。整数オーバーフロー計算を取得するために、unchecked-add-intとunchecked-multiply-intが使用されていることに注意してください。
(defn hash-ordered [collection]
(-> (reduce (fn [acc e] (unchecked-add-int
(unchecked-multiply-int 31 acc)
(hash e)))
1
collection)
(mix-collection-hash (count collection))))
順序付けられていない集合(マップ、セット)は、hasheqの計算に以下のアルゴリズムを使用する必要があります。マップのエントリは、キーと値の順序付き集合として扱われます。整数オーバーフロー計算を取得するために、unchecked-add-intが使用されていることに注意してください。
(defn hash-unordered [collection]
(-> (reduce unchecked-add-int 0 (map hash collection))
(mix-collection-hash (count collection))))
mix-collection-hashアルゴリズムは、変更される可能性のある実装の詳細です。
マップは、キーを値にマッピングする集合です。ハッシュマップとソート済みマップの2種類のマップが提供されています。ハッシュマップは、hashCodeとequalsを正しくサポートするキーを必要とします。ソート済みマップは、Comparableを実装するキー、またはComparatorのインスタンスを必要とします。ハッシュマップは、(logN回のジャンプ)と比較して、より高速なアクセス(log32N回のジャンプ)を提供しますが、ソート済みマップは、ソートされています。countはO(1)です。conjは、別の(おそらく単一のエントリの)マップをアイテムとして期待し、古いマップと新しいマップのエントリを合わせた新しいマップを返します。これは古いマップのエントリを上書きする可能性があります。conjは、MapEntryまたは2つのアイテム(キーと値)のベクターも受け入れます。seqは、キー/値ペアであるマップエントリのシーケンスを返します。ソート済みマップはrseqもサポートしており、これはエントリを逆順で返します。マップはIFnを実装しており、1つの引数(キー)とオプションの2番目の引数(デフォルト値)のinvoke()をサポートします。つまり、マップはそのキーの関数です。nilキーと値は問題ありません。
新しいマップを作成する:hash-map sorted-map sorted-map-by
マップを「変更する」:assoc dissoc select-keys merge merge-with zipmap
マップを調べる:get contains? find keys vals map?
マップのエントリを調べる:key val
StructMapsのほとんどの用途は、現在ではレコードの方が適しています。 |
多くのマップインスタンスは、同じ基本キーセットを持つことがよくあります。たとえば、マップが他の言語での構造体やオブジェクトとして使用される場合などです。StructMapsは、キー情報を効率的に共有しながら、それらのキーへのオプションの強化されたパフォーマンスアクセッサを提供することにより、このユースケースをサポートします。StructMapsはあらゆる点でマップであり、同じ関数セットをサポートし、他のすべてのマップと相互運用可能であり、永続的に拡張可能です(つまり、StructMapsは基本キーに限定されません)。唯一の制限は、StructMapの基本キーの1つをdissociateできないことです。StructMapは、基本キーを順序どおりに保持します。
StructMapsは、最初にcreate-structまたはdefstructを使用して構造体の基礎オブジェクトを作成し、次にstruct-mapまたはstructを使用してインスタンスを作成することによって作成されます。
(defstruct desilu :fred :ricky)
(def x (map (fn [n]
(struct-map desilu
:fred n
:ricky 2
:lucy 3
:ethel 4))
(range 100000)))
(def fred (accessor desilu :fred))
(reduce (fn [n y] (+ n (:fred y))) 0 x)
-> 4999950000
(reduce (fn [n y] (+ n (fred y))) 0 x)
-> 4999950000
StructMapの設定:create-struct defstruct accessor
個々の構造体を作成する:struct-map struct
コード形式操作を行う場合、キーの順序を維持するマップを持つことが望ましい場合があります。ArrayMapはそのようなマップであり、単にキー値キー値…の配列として実装されています。そのため、線形ルックアップパフォーマンスを持ち、非常に小さなマップにのみ適しています。これは完全なマップインターフェースを実装しています。array-map関数を使用して新しいArrayMapsを作成できます。ArrayMapは、「変更」されていない場合にのみソート順序を維持することに注意してください。後続のassocは最終的にハッシュマップになる原因となります。
セットは、一意の値の集合です。
ハッシュセットのリテラルサポートがあります。
#{:a :b :c :d}
-> #{:d :a :b :c}
hash-set関数とsorted-set関数を使用してセットを作成できます。
(hash-set :a :b :c :d)
-> #{:d :a :b :c}
(sorted-set :a :b :c :d)
-> #{:a :b :c :d}
set関数を使用して、集合内の値のセットを取得することもできます。
(set [1 2 3 2 1 2 3])
-> #{1 2 3}
セットは集合です。
(def s #{:a :b :c :d})
(conj s :e)
-> #{:d :a :b :e :c}
(count s)
-> 4
(seq s)
-> (:d :a :b :c)
(= (conj s :e) #{:a :b :c :d :e})
-> true
セットは、disjによる「削除」をサポートし、contains?とgetもサポートします。後者は、キーと等しく比較されるセットに保持されているオブジェクトを(見つかった場合)返します。
(disj s :d)
-> #{:a :b :c}
(contains? s :b)
-> true
(get s :a)
-> :a
セットは、getを使用して、そのメンバーの関数です。
(s :b)
-> :b
(s :k)
-> nil
Clojureは、union / difference / intersectionなどの基本的な集合演算と、単なるマップの集合である「関係」に対する擬似関係代数サポート(select / index / rename / join)を提供します。