(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))