(defrecord IndexedSet [elements indices])
(def empty-indexed-set (->IndexedSet #{} {}))
(defn add-index [iset name key]
(assoc-in iset [:indices name]
{:key key
:values (into {} (map (fn [x] [(key x) x])
(:elements iset)))}))
(defn add [iset value]
(reduce (fn [iset [name {key :key}]]
(update-in iset [:indices name :values]
assoc (key value) value))
(update iset
:elements
conj value
) (:indices iset)))
(defn lookup [iset name value]
(get-in iset [:indices name :values value]))
;; USAGE
(defrecord User [id name email-address])
(def elems
(-> empty-indexed-set
(add-index :id :id)
(add-index :email-address :email-address)
(add (->User 1 "elyse" "rightfold@gmail.com"))
(add (->User 2 "foo" "foo@bar.com"))
(add (->User 3 "bar" "fool@barl.com"))))
(-> elems (lookup :email-address "rightfold@gmail.com") (println))
(-> elems (lookup :id 3) (println))
KGRlZnJlY29yZCBJbmRleGVkU2V0IFtlbGVtZW50cyBpbmRpY2VzXSkKCihkZWYgZW1wdHktaW5kZXhlZC1zZXQgKC0+SW5kZXhlZFNldCAje30ge30pKQoKKGRlZm4gYWRkLWluZGV4IFtpc2V0IG5hbWUga2V5XQogIChhc3NvYy1pbiBpc2V0IFs6aW5kaWNlcyBuYW1lXQogICAgezprZXkga2V5CiAgICAgOnZhbHVlcyAoaW50byB7fSAobWFwIChmbiBbeF0gWyhrZXkgeCkgeF0pCiAgICAgICAgICAgICAgICAgICAgICAoOmVsZW1lbnRzIGlzZXQpKSl9KSkKCihkZWZuIGFkZCBbaXNldCB2YWx1ZV0KICAocmVkdWNlIChmbiBbaXNldCBbbmFtZSB7a2V5IDprZXl9XV0KICAgICAgICAgICAgKHVwZGF0ZS1pbiBpc2V0IFs6aW5kaWNlcyBuYW1lIDp2YWx1ZXNdCiAgICAgICAgICAgICAgYXNzb2MgKGtleSB2YWx1ZSkgdmFsdWUpKQogICAgICAgICAgKHVwZGF0ZSBpc2V0IDplbGVtZW50cyBjb25qIHZhbHVlKQogICAgICAgICAgKDppbmRpY2VzIGlzZXQpKSkKCihkZWZuIGxvb2t1cCBbaXNldCBuYW1lIHZhbHVlXQogIChnZXQtaW4gaXNldCBbOmluZGljZXMgbmFtZSA6dmFsdWVzIHZhbHVlXSkpCgo7OyBVU0FHRQoKKGRlZnJlY29yZCBVc2VyIFtpZCBuYW1lIGVtYWlsLWFkZHJlc3NdKQoKKGRlZiBlbGVtcwogICgtPiBlbXB0eS1pbmRleGVkLXNldAogICAgICAoYWRkLWluZGV4IDppZCA6aWQpCiAgICAgIChhZGQtaW5kZXggOmVtYWlsLWFkZHJlc3MgOmVtYWlsLWFkZHJlc3MpCiAgICAgIChhZGQgKC0+VXNlciAxICJlbHlzZSIgInJpZ2h0Zm9sZEBnbWFpbC5jb20iKSkKICAgICAgKGFkZCAoLT5Vc2VyIDIgImZvbyIgImZvb0BiYXIuY29tIikpCiAgICAgIChhZGQgKC0+VXNlciAzICJiYXIiICJmb29sQGJhcmwuY29tIikpKSkKKC0+IGVsZW1zIChsb29rdXAgOmVtYWlsLWFkZHJlc3MgInJpZ2h0Zm9sZEBnbWFpbC5jb20iKSAocHJpbnRsbikpCigtPiBlbGVtcyAobG9va3VwIDppZCAzKSAocHJpbnRsbikp