I\'m sure there\'s a good reason, but could someone please explain why the java.util.Set
interface lacks get(int Index)
, or any similar get()
I ran into situations where I actually wanted a SortedSet with access via index (I concur with other posters that accessing an unsorted Set with an index makes no sense). An example would be a tree where I wanted the children to be sorted and duplicate children were not allowed.
I needed the access via index to display them and the set attributes came in handy to efficiently eliminate duplicates.
Finding no suitable collection in java.util or google collections, I found it straightforward to implement it myself. The basic idea is to wrap a SortedSet and create a List when access via index is required (and forget the list when the SortedSet is changed). This does of course only work efficiently when changing the wrapped SortedSet and accessing the list is separated in the lifetime of the Collection. Otherwise it behaves like a list which is sorted often, i.e. too slow.
With large numbers of children, this improved performance a lot over a list I kept sorted via Collections.sort.
The only reason I can think of for using a numerical index in a set would be for iteration. For that, use
for(A a : set) {
visit(a);
}
Please note only 2 basic data structure can be accessed via index.
O(1)
time complexity to achieve get(int index)
operation.O(n)
time complexity to achieve get(int index)
operation.In Java, ArrayList
is implemented using Array data structure.
While Set data structure usually can be implemented via HashTable/HashMap or BalancedTree data structure, for fast detecting whether an element exists and add non-existing element, usually a well implemented Set can achieve O(1)
time complexity contains
operation. In Java, HashSet
is the most common used implementation of Set, it is implemented by calling HashMap
API, and HashMap
is implemented using separate chaining with linked lists (a combination of Array and LinkedList).
Since Set can be implemented via different data structure, there is no get(int index)
method for it.
If you are going to do lots of random accesses by index in a set, you can get an array view of its elements:
Object[] arrayView = mySet.toArray();
//do whatever you need with arrayView[i]
There are two main drawbacks though:
Set is an interface and some of its implementation classes are HashSet, TreeSet and LinkedHashSet. It uses HashMap under the hood to store values. Because HashMap does not preserve the order, it is not possible to get value by index.
You now must be thinking how Set is using HashMap since HashMap stores a key, value pair but the Set does not. valid question. when you add an element in Set, internally, it maintains a HashMap where the key is the element you want to enter in Set and the value is the dummy constant. Below is an internal implementation of add function. Hence, all the keys in the HashMap will have the same constant value.
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
Just adding one point that was not mentioned in mmyers' answer.
If I know I want the first item, I can use set.iterator().next(), but otherwise it seems I have to cast to an Array to retrieve an item at a specific index?
What are the appropriate ways of retrieving data from a set? (other than using an iterator)
You should also familiarise yourself with the SortedSet interface (whose most common implementation is TreeSet).
A SortedSet is a Set (i.e. elements are unique) that is kept ordered by the natural ordering of the elements or using some Comparator
. You can easily access the first and last items using first()
and last()
methods. A SortedSet
comes in handy every once in a while, when you need to keep your collection both duplicate-free and ordered in a certain way.
Edit: If you need a Set whose elements are kept in insertion-order (much like a List), take a look at LinkedHashSet.