multiset icon indicating copy to clipboard operation
multiset copied to clipboard

Set equality

Open emlyn opened this issue 8 years ago • 3 comments

I think it would make sense for a multiset to equal a set when the elements are the same. This PR implements that (in both directions): (= set multiset) is enabled by making multiset implement the java.util.Set interface, and (= multiset set) is handled in the .equals method.

I also changed the .hashCode algorithm to match that used by java.util.Set, and added support for Clojure's hash algorithm, so that when a set and a multiset are equal, their (Java and Clojure) hashes will also be equal.

Does this look reasonable to you?

emlyn avatar Sep 06 '17 14:09 emlyn

Ping @achim: any feedback on this? I think it makes sense (as, for example, (= [1 2 3] '(1 2 3)) is also true, even if they have different types). It also makes it easier to use multisets in tests, as you can just compare to a set literal when you don't expect any duplicates, e.g.:

(defn foo
  [c]
  (into (multiset)
        (map #(* % 2) c)))

(deftest foo-test
  (is (= (foo [1 2 3])
         #{2 4 6})))

emlyn avatar Sep 13 '17 10:09 emlyn

@emlyn Thanks for the PR! I'm sorry for the delay, I'll hopefully have a chance to look at this on the weekend.

achim avatar Sep 13 '17 10:09 achim

I just realised there is a slight issue in the equality comparison to a java.util.Set in that it assumes the elements of the other set are distinct. That might not be the case if it is another multiset (although it would have to be a different implementation as this one is already handled).

So I've changed the equality check so that it works even if the other set has duplicate elements. I've then added special cases for Clojure sets and AbstractSets so that in the most common cases it can use the faster check (although I haven't benchmarked it, so maybe those two cases aren't really needed?).

emlyn avatar Sep 18 '17 10:09 emlyn