Sorted Collection in Java
I'm a Beginner in Java. Please Suggest Which Collection(S) Can/Should Be Used for Maintaining a Sorted List in Java. I Have Tried Map and Set, but They Weren't...
I'm a beginner in Java. Please suggest which collection(s) can/should be used for maintaining a sorted list in Java. I have tried Map and Set, but they weren't what I was looking for.
21 Answers
This comes very late, but there is a class in the JDK just for the purpose of having a sorted list. It is named (somewhat out of order with the other Sorted* interfaces) "java.util.PriorityQueue". It can sort either Comparable<?>s or using a Comparator.
The difference with a List sorted using Collections.sort(...) is that this will maintain a partial order at all times, with O(log(n)) insertion performance, by using a heap data structure, whereas inserting in a sorted ArrayList will be O(n) (i.e., using binary search and move).
However, unlike a List, PriorityQueue does not support indexed access (get(5)), the only way to access items in a heap is to take them out, one at a time (thus the name PriorityQueue).
TreeMap and TreeSet will give you an iteration over the contents in sorted order. Or you could use an ArrayList and use Collections.sort() to sort it. All those classes are in java.util
Use Google Guava's TreeMultiset class. Guava has a spectacular collections API.
One problem with providing an implementation of List that maintains sorted order is the promise made in the JavaDocs of the add() method.
If you want to maintain a sorted list which you will frequently modify (i.e. a structure which, in addition to being sorted, allows duplicates and whose elements can be efficiently referenced by index), then use an ArrayList but when you need to insert an element, always use Collections.binarySearch() to determine the index at which you add a given element. The latter method tells you the index you need to insert at to keep your list in sorted order.
There are a few options. I'd suggest TreeSet if you don't want duplicates and the objects you're inserting are comparable.
You can also use the static methods of the Collections class to do this.
See Collections#sort(java.util.List) and TreeSet for more info.
If you just want to sort a list, use any kind of List and use Collections.sort(). If you want to make sure elements in the list are unique and always sorted, use a SortedSet.
What I have done is implement List having a internal instance with all the methods delegated.
public class ContactList implements List<Contact>, Serializable {
private static final long serialVersionUID = -1862666454644475565L;
private final List<Contact> list;
public ContactList() {
super();
this.list = new ArrayList<Contact>();
}
public ContactList(List<Contact> list) {
super();
//copy and order list
List<Contact>aux= new ArrayList(list);
Collections.sort(aux);
this.list = aux;
}
public void clear() {
list.clear();
}
public boolean contains(Object object) {
return list.contains(object);
}
After, I have implemented a new method "putOrdered" which insert in the proper position if the element doesn't exist or replace just in case it exist.
public void putOrdered(Contact contact) {
int index=Collections.binarySearch(this.list,contact);
if(index<0){
index= -(index+1);
list.add(index, contact);
}else{
list.set(index, contact);
}
}
If you want to allow repeated elements just implement addOrdered instead (or both).
public void addOrdered(Contact contact) {
int index=Collections.binarySearch(this.list,contact);
if(index<0){
index= -(index+1);
}
list.add(index, contact);
}
If you want to avoid inserts you can also throw and unsupported operation exception on "add" and "set" methods.
public boolean add(Contact object) {
throw new UnsupportedOperationException("Use putOrdered instead");
}
... and also You have to be careful with ListIterator methods because they could modify your internal list. In this case you can return a copy of the internal list or again throw an exception.
public ListIterator<Contact> listIterator() {
return (new ArrayList<Contact>(list)).listIterator();
}
The most efficient way to implement a sorted list like you want would be to implement an indexable skiplist as in here: Wikipedia: Indexable skiplist. It would allow to have inserts/removals in O(log(n)) and would allow to have indexed access at the same time. And it would also allow duplicates.
Skiplist is a pretty interesting and, I would say, underrated data structure. Unfortunately there is no indexed skiplist implementation in Java base library, but you can use one of open source implementations or implement it yourself. There are regular Skiplist implementations like ConcurrentSkipListSet and ConcurrentSkipListMap
TreeSet would not work because they do not allow duplicates plus they do not provide method to fetch element at specific position. PriorityQueue would not work because it does not allow fetching elements at specific position which is a basic requirement for a list. I think you need to implement your own algorithm to maintain a sorted list in Java with O(logn) insert time, unless you do not need duplicates. Maybe a solution could be using a TreeMap where the key is a subclass of the item overriding the equals method so that duplicates are allowed.
Must Read
Using LambdaJ
You can try solving these tasks with LambdaJ if you are using prior versions to java 8. You can find it here:
Here you have an example:
Sort Iterative
List<Person> sortedByAgePersons = new ArrayList<Person>(persons);
Collections.sort(sortedByAgePersons, new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
}
});
Sort with LambdaJ
List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge());
Of course, having this kind of beauty impacts in the performance (an average of 2 times), but can you find a more readable code?