Sets¶
Three sets with the same operations: add, remove, contains, union, intersect, diff, and the usual
filter, map and fold. They differ in how they order their elements.
| Type | Representation | Iteration order | Positional methods |
|---|---|---|---|
HashSet |
a hash-based tree | not defined | none |
LinkedHashSet |
a hash-based set that also records the insertion order | insertion order | yes |
TreeSet |
a sorted, balanced tree | the comparator's | yes |
When to choose which¶
HashSetby default.LinkedHashSetwhen the order the elements arrived in matters, for example to remove duplicates from a sequence and keep its order.TreeSetwhen you need the elements sorted, a range of them, or the least and the greatest.
HashSet<String> tags = HashSet.of("java", "scala");
HashSet<String> more = tags.add("zio").remove("scala");
HashSet<String> common = tags.intersect(HashSet.of("scala", "kotlin"));
// more contains java and zio, common is HashSet(scala)
LinkedHashSet<String> seen = LinkedHashSet.of("b", "a").add("c").add("a");
TreeSet<Integer> sorted = TreeSet.of(5, 1, 4, 2);
Integer smallest = sorted.head();
TreeSet<Integer> firstTwo = sorted.take(2);
// seen is LinkedHashSet(b, a, c), smallest is 1, firstTwo is TreeSet(1, 2)
Costs¶
| Operation | Cost | Note |
|---|---|---|
contains |
effectively O(1) | effectively O(1) (one hash lookup). |
add |
effectively O(1) | effectively O(1) (one hash lookup, then a path copy of the trie when the element is new). |
remove |
effectively O(1) | effectively O(1) (one hash lookup and a path copy of the trie). |
union |
O(m) | O(m) for a set of m elements, each an effectively O(1) insertion; this set or a HashSet argument is returned as is when the other side is empty. |
intersect |
O(n + m) | O(n + m) for a set of m elements (the smaller set is filtered against a hash set of the larger one). |
diff |
O(n + m) | O(n + m) for a set of m elements (a hash set of them, then one filter pass). |
min |
O(n) | O(n), every element compared once in natural order; on a TreeSet the least element in the comparator's order is head(), O(log n). |
max |
O(n) | O(n), every element compared once in natural order; on a TreeSet the greatest element in the comparator's order is last(), O(log n). |
| Operation | Cost | Note |
|---|---|---|
contains |
effectively O(1) | effectively O(1) (one hash lookup). |
add |
effectively O(1) | effectively O(1) (one hash lookup, then a hash insertion and an append to the insertion order when the element is new). |
remove |
effectively O(1) | effectively O(1) (one hash removal and one marker in the insertion order), amortised: when the markers outnumber the elements, the insertion order is rebuilt in O(n). |
union |
O(m) | O(m) for a set of m elements, each an effectively O(1) add(Object). |
intersect |
O(n + m) | O(n + m) for a set of m elements (a hash set of them, then the kept elements copied into a new set). |
diff |
O(n + m) | O(n + m) for a set of m elements (a hash set of them, then the kept elements copied into a new set). |
min |
O(n) | O(n), every element compared once in natural order; on a TreeSet the least element in the comparator's order is head(), O(log n). |
max |
O(n) | O(n), every element compared once in natural order; on a TreeSet the greatest element in the comparator's order is last(), O(log n). |
head |
effectively O(1) | effectively O(1) (the first element of the insertion order). |
take |
effectively O(min(n, size - n)) | effectively O(min(n, size - n)) (the smaller of the kept and the removed elements is inserted into or removed from the hash map; the insertion order is sliced). After removals, finding the cut also walks the insertion order from the nearer end past the removed elements' markers. |
drop |
effectively O(min(n, size - n)) | effectively O(min(n, size - n)), that of take(int). |
| Operation | Cost | Note |
|---|---|---|
contains |
O(log n) | O(log n) comparisons. |
add |
O(log n) | O(log n) (one lookup, then one insertion in the tree when the element is new). |
remove |
O(log n) | O(log n) (one deletion from the tree). |
union |
O(m log(n + m)) | O(m log(n + m)) for a set of m elements: a split and a join per node of elements when it is a TreeSet with the same comparator, otherwise one lookup and one insertion per element. |
intersect |
O((n + m) log n) | O((n + m) log n) for a set of m elements: a split and a join per node of elements when it is a TreeSet with the same comparator, otherwise a hash set of elements and the kept elements built into a new tree. |
diff |
O((n + m) log n) | O((n + m) log n) for a set of m elements: a split and a join per node of elements when it is a TreeSet with the same comparator, otherwise a hash set of elements and the kept elements built into a new tree. |
min |
O(n) | O(n), every element compared once in natural order; on a TreeSet the least element in the comparator's order is head(), O(log n). |
max |
O(n) | O(n), every element compared once in natural order; on a TreeSet the greatest element in the comparator's order is last(), O(log n). |
head |
O(log n) | O(log n) (the leftmost path of the tree). |
take |
O(log n) | O(log n) (one rank split of the tree). |
drop |
O(log n) | O(log n) (one rank split of the tree). |
Every method: complexity page.
Positional methods¶
LinkedHashSet and TreeSet have a defined order, so they have the methods that depend on it: head, last,
tail, take, drop, zipWithIndex, sliding, grouped and their variants.
HashSet has none of them, because its order is not defined.
Sharp edges¶
- Do not rely on the iteration order of a
HashSet: it depends on the hashes and may change between versions.foldandreducesee the elements in that order, so give them an operation where the order does not matter. max()andmin()use the natural order of the elements, which must beComparable, and walk them all, even on aTreeSet. The least and greatest elements in aTreeSet's own order arehead()andlast(), in O(log n).TreeSetdecides membership with its comparator, notequals.union,intersectanddiffare fast on twoTreeSets with the same comparator. With different comparators, or another kind of set, they process the elements one by one.TreeSethas nopartitionMap.