elmcraft / core-extra

Utility functions for an improved experience with elm/core
https://package.elm-lang.org/packages/elmcraft/core-extra/latest/
Other
23 stars 11 forks source link

Add Set.Extra.symmetricDifference, isSuperset, areDisjoint #38

Closed gampleman closed 7 months ago

gampleman commented 7 months ago

symmetricDifference : Set a -> Set a -> Set a

The symmetric difference between two sets is a set that contains all the elements that are in one of the two sets, but not both.

(image of Venn diagram such as:

could perhaps be useful).

isSuperset : Set a -> Set a -> Bool

A set is a superset of another set if all the elements in the second set appear in the first set.

isSubset : Set a -> Set a -> Bool

This is the existing Set.Extra.subset, but with a better name.

areDisjoint : Set a -> Set a -> Bool

A set is disjoint from another set if they have no elements in common.

Motivating use case

These are fairly standard set operations that just seem missing. Symmetric difference is basically an SQL FULL OUTER JOIN. areDisjoint can easily come up if the user is supposed to select checkboxes in two lists, but can't select an item in both lists.

The weakest is isSuperset, since it's exactly the same as isSubset, but with the arguments flipped.

Rationale

Implementing these in user land is simple, albeit I'd bet more efficient algorithms exist:

symmetricDifference a b = 
   Set.difference (Set.union a b) (Set.intersection a b)

isSuperset a b =
   isSubset b a

areDisjoint a b =
   Set.intersection a b == Set.empty

Also, JavaScript is getting these natively soon.

miniBill commented 7 months ago

I'd rather name them isSubsetOf and isSupersetOf so the order is clearer. I always have to look up Set.diff to know the order.

Edit: and yes, vastly more efficient algorithms exist if you can access the internals.

gampleman commented 7 months ago

@miniBill how does the Of suffix clarify the order? Is is still the case that isSubsetOf a b --> True means a is a subset of b?

I find the Of suffix more confusing in pipeline style:

a
    |> Set.isSubsetOf b

is more confusing than

a 
   |> Set.isSubset b

we could of course flip the arguments vs the existing function while we're making this change....

miniBill commented 7 months ago

I read a |> Set.isSubsetOf b as "a is a subset of b", which is what I think the implementation should do.

I see you've fixed it in #39