Skip to content

Latest commit

 

History

History
768 lines (705 loc) · 33.6 KB

clojure-collections-comparison.org

File metadata and controls

768 lines (705 loc) · 33.6 KB

https://github.com/slk500/clojure-collections-comparison is open for MR.

legend:

  • ‘1’ means minimal data provided e.g (list 1), (vector 1), (hash-map :a 1)
  • ‘coll’ is one of data type: list, vector, hash-set, sorted-set, hash-map. Because everyone of them is a collection.
itemlistvectorhash-setsorted-sethash-mapsorted-map
“literal syntax”()[ ]#{}#{}{}{}
create from args(list 1 2 3)(vector 1 2 3)(hash-set 2 3 1)(sorted-set 1 2 3)(hash-map :b 2 :c 3 :a 1)(sorted-map :a 1 :b 2 :c 3)
create from collection(apply list [1 2 3])(vec ‘(1 2 3))(set ‘(2 3 1))(apply sorted-set [2 3 1])(into (hash-map) {:a 1 :b 2 :c 3})(into (sorted-map) {:a 1 :b 2 :c 3})
(coll? coll)truetruetruetruetruetrue
(sequential? coll)truetruefalsefalsefalsefalse
(associative? coll)falsetruefalsefalsetruetrue
(type coll)PersistentList$EmptyListPersistentVectorPersistentHashSetPersistentTreeSetPersistentArrayMapPersistentTreeMap
(type (coll 1))PersistentListPersistentVectorPersistentHashSetPersistentTreeSetPersistentArrayMapPersistentTreeMap
(list? coll)truefalsefalsefalsefalsefalse
(vector? coll)falsetruefalsefalsefalsefalse
(set? coll)falsefalsetruetruefalsefalse
(map? coll)falsefalsefalsefalsetruetrue
(seq? coll)truefalsefalsefalsefalsefalse
(seq? (coll 1))truefalsefalsefalsefalsefalse
(seq? (seq coll))falsefalsefalsefalsefalsefalse
(seq? (seq (coll 1))truetruetruetruetruetrue
(type (seq coll))nilnilnilnilnilnil
(type (sequence coll)PersistentList$EmptyListPersistentList$EmptyListPersistentList$EmptyListPersistentList$EmptyListPersistentList$EmptyListPersistentList$EmptyList
(type (sequence (coll 1)))PersistentListPersistentVector$ChunkedSeqAPersistentMap$KeySeqAPersistentMap$KeySeqPersistentHashMap$NodeSeqPersistentTreeMap$Seq
(type (seq (coll 1)))PersistentListPersistentVector$ChunkedSeqAPersistentMap$KeySeqAPersistentMap$KeySeqPersistentHashMap$NodeSeqPersistentTreeMap$Seq
“unique elements”falsefalsetruetruetrue (only keys)true (only keys)
“same order of elements”truetruefalsetruefalsetrue
“read”nthget, IFn, nthget, IFn, keyget, IFn, key
(get coll 1)nilnilnilnilnilnil
(get (coll 1) 1)niltrue (index)uselessuselesstrue (key)true (key)
(get nil 1)nilnilnilnilnilnil
“get out of range”nil or not-foundnil or not-foundnil or not-foundnil or not-foundnil or not-foundnil or not-found
“IFn”error([:a :b :c] 1) => :berrorerror({:b 2 :c 3 :a 1} :b) => 2({:a 1 :b 2 :c 3} :a) => 1
“IFn out of range”errorerrorerrorerrornilnil
“nth”truetruetruetrueerrorerror
(nth nil 1)nil
“nth out of range”
“add”cons, conjassocassoc
“conj (coll)”frontbackvaryvaryvaryvary
“cons (seq)”frontfrontvaryvaryvaryvary
“remove”disjdissoc
“contains?”errortrue (index)true (element)true (element)true (key)true (key)

“literal syntax”

(type '()) ;=> PersistentList$EmptyList

create from args

create from collection

(apply list [1 2 3]) ;=> (1 2 3)
(apply sorted-set [2 3 1]) ;=> #{1 2 3}
(into (hash-map) {:a 1 :b 2}) ;=> {:a 1, :b 2}
(into (sorted-map) {:b 2 :c 3 :a 1}) ;=> {:a 1, :b 2, :c 3}

(coll? coll)

(coll? (list)) ; => true
(coll? (vector))  ; => true
(coll? (hash-set)) ; => true
(coll? (sorted-set))  ; => true
(coll? (hash-map)) ; => true
(coll? (sorted-map))  ; => true

(sequential? coll)

Returns true if coll implements Sequential

Definitions from Oxford Languages: sequential - forming or following in a logical order or sequence.

(sequential? (list)) ;=> true
(sequential? (vector)) ;=> true
(sequential? (hash-set)) ;=> false
(sequential? (sorted-set)) ;=> false
(sequential? (hash-map)) ;=> false
(sequential? (sorted-map)) ;=> false

I was thinking that sorted-set & sorted-map are (= sequential? true) They have logical order (they are sorted) so why they are not sequential?

dgb23 hashed collections have sequence representations (map entries) that are sequential. I think it is more of an implementation thing. In theory you’re right, they are both sequential and hashed collections.

phill The sequential? docstring tells me nothing about what it does! I do not see a basis for expectation of any particular return value. It would be a good question for ask.clojure.org so it might get clarified. However, it would be normal for sequential? to mean “preserves the order of insertion?” which vectors do (expect true), lists do in reverse (expect -true), and sets and maps never do (expect false). (edited)

dgb23 Sequential is an empty interface. I think it’s just a signal that is put on certain implementations.

(associative? coll)

Returns true if coll implements Associative
(associative? (list)) ;=> false
(associative? (vector)) ;=> true
(associative? (hash-set)) ;=> false
(associative? (sorted-set)) ;=> false
(associative? (hash-map)) ;=> true
(associative? (sorted-map)) ;=> true

(type coll)

Returns the :type metadata of x, or its Class if none
(type (list)) ;=> Persistentlist$EmptyList
(type (vector)) ;=> PersistentVector
(type (hash-set)) ;=> PersistentHashSet
(type (sorted-set)) ;=> PersistentTreeSet
(type (hash-map)) ;=> PersistentArrayMap
(type (sorted-map)) ;=> PersistentTreeMap

(type (coll 1))

(type (list 1)) ;=> Persistentlist
(type (vector 1)) ;=> PersistentVector
(type (hash-set 1)) ;=> PersistentHashSet
(type (sorted-set 1)) ;=> PersistentTreeSet
(type (hash-map :a 1)) ;=> PersistentHashMap
(type (sorted-map :a 1)) ;=> PersistentTreeMap

(list? coll)

Returns true if x implements IPersistentlist
(list? (list)) ;=> true
(list? (vector)) ;=> false
(list? (hash-set)) ;=> false
(list? (sorted-set)) ;=> false
(list? (hash-map)) ;=> false
(list? (sorted-map)) ;=> false

(vector? coll)

Return true if x implements IPersistentVector
(vector? (list)) ;=> false
(vector? (vector)) ;=> true
(vector? (hash-set)) ;=> false
(vector? (sorted-set)) ;=> false
(vector? (hash-map)) ;=> false
(vector? (sorted-map)) ;=> false

(set? coll)

(set? (list)) ;=> false
(set? (vector)) ;=> false
(set? (hash-set)) ;=> true
(set? (sorted-set)) ;=> true
(set? (hash-map)) ;=> false
(set? (sorted-map)) ;=> false

(map? coll)

(map? (list)) ;=> false
(map? (vector)) ;=> false
(map? (hash-set)) ;=> false
(map? (sorted-set)) ;=> false
(map? (hash-map)) ;=> true
(map? (sorted-map)) ;=> true

(seq? coll)

Return true if x implements ISeq
(seq? (list)) ;=> true
(seq? (vector)) ;=> false
(seq? (hash-set)) ;=> false
(seq? (sorted-set)) ;=> false
(seq? (hash-map)) ;=> false
(seq? (sorted-map)) ;=> false

(seq? (coll 1))

Return true if x implements ISeq
(seq? (list 1)) ;=> true
(seq? (vector 1)) ;=> false
(seq? (hash-set 1)) ;=> false
(seq? (sorted-set 1)) ;=> false
(seq? (hash-map :a 1)) ;=> false
(seq? (sorted-map :a 1)) ;=> false

(seq? (seq coll))

(seq? (seq (list))) ;=> false
(seq? (seq (vector))) ;=> false
(seq? (seq (hash-set))) ;=> false
(seq? (seq (sorted-set))) ;=> false
(seq? (seq (hash-map))) ;=> false
(seq? (seq (sorted-map))) ;=> false

(seq? (seq (coll 1))

(seq? (seq (list 1))) ;=> true
(seq? (seq (vector 1))) ;=> true
(seq? (seq (hash-set 1))) ;=> true
(seq? (seq (sorted-set 1))) ;=> true
(seq? (seq (hash-map :a 1))) ;=> true
(seq? (seq (sorted-map :a 1))) ;=> true

(type (seq coll))

clojure.core/seq ([coll])

Returns a seq on the collection. If the collection is empty, returns nil. (seq nil) returns nil. seq also works on Strings, native Java arrays (of reference types) and any objects that implement Iterable. Note that seqs cache values, thus seq should not be used on any Iterable whose iterator repeatedly returns the same mutable object.

(type (seq (list))) ;=> nil
(type (seq (vector))) ;=> nil
(type (seq (hash-set))) ;=> nil
(type (seq (sorted-set))) ;=> nil
(type (seq (hash-map))) ;=> nil
(type (seq (sorted-map))) ;=> nil

(type (sequence coll)

clojure.core/sequence ([coll] [xform coll] [xform coll & colls]) Coerces coll to a (possibly empty) sequence, if it is not already one. Will not force a lazy seq. (sequence nil) yields (), When a transducer is supplied, returns a lazy sequence of applications of the transform to the items in coll(s), i.e. to the set of first items of each coll, followed by the set of second items in each coll, until any one of the colls is exhausted. Any remaining items in other colls are ignored. The transform should accept number-of-colls arguments
(type (sequence (list))) ;=> PersistentList$Emptylist
(type (sequence (vector))) ;=> PersistentList$Emptylist
(type (sequence (hash-set))) ;=> PersistentList$Emptylist
(type (sequence (sorted-set))) ;=> PersistentList$Emptylist
(type (sequence (hash-map))) ;=> PersistentList$Emptylist
(type (sequence (sorted-map))) ;=> PersistentList$Emptylist

(type (sequence (coll 1)))

clojure.core/sequence ([coll] [xform coll] [xform coll & colls]) Coerces coll to a (possibly empty) sequence, if it is not already one. Will not force a lazy seq. (sequence nil) yields (), When a transducer is supplied, returns a lazy sequence of applications of the transform to the items in coll(s), i.e. to the set of first items of each coll, followed by the set of second items in each coll, until any one of the colls is exhausted. Any remaining items in other colls are ignored. The transform should accept number-of-colls arguments
(type (sequence (list 1))) ;=> PersistentList
(type (sequence (vector 1))) ;=> PersistentVector$ChunkedSequence
(type (sequence (hash-set 1))) ;=> APersistentMap$KeySequence
(type (sequence (sorted-set 1))) ;=> APersistentMap$KeySequence
(type (sequence (hash-map :a 1))) ;=> PersistentHashMap$NodeSequence
(type (sequence (sorted-map :a 1))) ;=> PersistentTreeMap$Sequence

(type (seq (coll 1)))

clojure.core/seq ([coll])

Returns a seq on the collection. If the collection is empty, returns nil. (seq nil) returns nil. seq also works on Strings, native Java arrays (of reference types) and any objects that implement Iterable. Note that seqs cache values, thus seq should not be used on any Iterable whose iterator repeatedly returns the same mutable object.

(type (seq (list 1))) ;=> Persistentlist
(type (seq (vector 1))) ;=> PersistentVector$ChunkedSeq
(type (seq (hash-set 1))) ;=> APersistentMap$KeySeq
(type (seq (sorted-set 1))) ;=> APersistentMap$KeySeq
(type (seq (hash-map :a 1))) ;=> PersistentHashMap$NodeSeq
(type (seq (sorted-map :a 1))) ;=> PersistentTreeMap$Seq

“unique elements”

“same order of elements”

“read”

You cannot use the get function with a list to retrieve by index.

(get coll 1)

([map key] [map key not-found])
(get (list) 1) ;=> nil
(get (vector) 1) ;=> nil
(get (hash-set) 1) ;=> nil
(get (sorted-set) 1) ;=> nil
(get (hash-map) :a) ;=> nil
(get (sorted-map) :a) ;=> nil

(get (coll 1) 1)

([map key] [map key not-found])
 (get (list :a :b) 0) ;=> nil
 (get (list :a :b) :a) ;=> nil
 (get (list :a :b) "string") ;=> nil
; Although lists are sequences, they are not keyed sequences.

 (get (vector :a :b) 0) ;=> :a
 (get (vector :a :b) 1) ;=> :b

 (get (hash-set :a :b) 0) ;=> nil
 (get (hash-set :a :b) 1) ;=> nil
 (get (hash-set :a :b) :a) ;=> :a
 (get (hash-set :a :b) "string") ;=> nil

 (get (sorted-set :a :b) 0) ;=> Unhandled java.lang.ClassCastException
 (get (sorted-set :a :b) 1) ;=> Unhandled java.lang.ClassCastException
 (get (sorted-set :a :b) "string") ;=> Unhandled java.lang.ClassCastException
 (get (sorted-set :a :b) :a) ;=> :a
 (get (sorted-set :a :b) :b) ;=> :a

 (get (hash-map :a 1 :b 2) :a) ;=> 1
 (get (hash-map :a 1 :b 2) 1) ;=> nil
 (get (sorted-map :a 1 :b 2) :a) ;=> 1
 (get (sorted-map :a 1 :b 2) 1) ;=> ;=> Unhandled java.lang.ClassCastException

(get nil 1)

(get nil 1) ; => nil

“get out of range”

“IFn”

('(1 2 3) 1) ; class clojure.lang.PersistentList cannot be cast to class clojure.lang.IFn (clojure.lang.PersistentList and clojure.lang.IFn

([1 2 3] 1) ;=> 2

(#(1 2 3) 2) ;=> error

‘IFn’ means ‘Interface Function’. Keywords also have this interface. In the preceding examples, we can see that a list that is not quoted with ’ throws an error unless the first item of the list can be invoked as a function.

({:a 1 :b 2 :c 3} :a); => 1 | maps are functions of their keys
(:a {:a 1 :b 2 :c 3}) ; => 1 | keywords are also functions

(1 [:b :c :a]) ;=> error
([:b :c :a] 1) ;=> :c
(:c [:b :c :a]) ;=> nil

(nil 0) ; => IllegalArgumentException

“IFn out of range”

([:a :b] 2) ;=> IndexOutOfBoundsException
({:a 1 :b 2} :c); => nil

“nth”

([coll index] [coll index not-found]) throws an exception unless not-found is supplied

Using nth to retrieve an element from a list is slower than using get to retrieve an element from a vector.

(nth (list :a :b) 0) ;=> :a
(nth (list :a :b) 1) ;=> :b
(nth (list :a :b) 3) ;=> Unhandled java.lang.IndexOutOfBoundsException

(nth (vector :a :b) 0) ;=> :a
(nth (vector :a :b) 1) ;=> :b

(nth (hash-set :a :b) 0) ;=> Unhandled java.lang.UnsupportedOperationException

(nth (sorted-set :a :b) 0) ;=> Unhandled java.lang.UnsupportedOperationException

(nth (hash-map :a 1 :b 2) 0) ;=> Unhandled java.lang.UnsupportedOperationException

(nth nil 1)

(nth nil 1) ; => nil

“nth out of range”

“add”

“conj (coll)”

(conj [1 2 3] 4) ; => [1 2 3 4]

“cons (seq)”

(cons "two" (list "first")) ;=> ("two" "first")
(cons "two" (vector "first"))  ;=> ("two" "first")
(cons "two" (hash-set "first"))  ;=> ("two" "first")
(cons "two" (sorted-set "first"))  ;=> ("two" "first")

“remove”

“contains?”

(contains? '(1 2 4 3) 4)
;=> IllegalArgumentException

(contains? [1 2 3 4] 0) ;=> true
(contains? [1 2 3 4] 4) ;=> false

(contains? #{1 2 3 4} 0) ;=> false
(contains? #{1 2 3 4} 4) ;=> true

(contains? {:a 1 :b 2} :a) ;=> true
(contains? {:a 1 :b 2} 1) ;=> true