59

I have a generic Collection and am trying to work out how I can sort the items contained within it. I've tried a few things but I can't get any of them working.

8 Answers 8

77

Collections by themselves do not have a predefined order, therefore you must convert them to a java.util.List. Then you can use one form of java.util.Collections.sort

Collection< T > collection = ...; List< T > list = new ArrayList< T >( collection ); Collections.sort( list ); // or Collections.sort( list, new Comparator< T >( ){...} ); // list now is sorted 
Sign up to request clarification or add additional context in comments.

5 Comments

Although this solves the problem, this will not be the fastest way to do this, unless the collection itself is already a List.
@Fortega: Then enlighten me what IS the fastest way to sort a general Collection while retaining all of its elements. BTW, this is exactly the method used by Google Collections Ordering.sortedCopy.
It depends on the type of the collection. For collections of which the toArray() method (called in constructor of ArrayList) needs iteration over all the elements (for example: a Set), sorting might need an extra loop over all elements. You could use google collections TreeMultiset, which allows duplicates. Although the differences will probably be not very big and in the same order of magnitude.
What happens at the ellipsis? I have a Download class and tried Collection<Download> colls = new Collection<Download>(); and get an instantiation error.
@gwg - You cannot instantiate a Collection, it is an abstract class. You can, however, assign anything that extends collection to a local variable of type Collection.
10

A Collection does not have an ordering, so wanting to sort it does not make sense. You can sort List instances and arrays, and the methods to do that are Collections.sort() and Arrays.sort()

Comments

7

You have two basic options provided by java.util.Collections:

Depending on what the Collection is, you can also look at SortedSet or SortedMap.

Comments

6

If your collections object is a list, I would use the sort method, as proposed in the other answers.

However, if it is not a list, and you don't really care about what type of Collection object is returned, I think it is faster to create a TreeSet instead of a List:

TreeSet sortedSet = new TreeSet(myComparator); sortedSet.addAll(myCollectionToBeSorted); 

4 Comments

TreeSet requires Comparable to be implemented, if you want the set sorted. This is what I usually do when I need a sorted Collection. TreeSet will also throw away duplicates.
TreeSet does not require Comparable to be implemented if you use a Comparator. However, you are right about the duplicates.
OOPS- missed the comparator sitting in there. I always implement Comparable, so I missed it completely.
Note that a TreeSet is feasible only when the collection does not contain duplicates. Also, populating an ArrayList and then sorting it is faster than populating a TreeSet. Though both approaches are O(N log N), a TreeSet has a higher constant factor because of the red-black tree manipulations and the larger number of memory allocations. Still, I sometimes use a TreeSet to make my code more concise, even though that's slower than using an ArrayList.
5

You can't if T is all you get. It must be injected by the provider:

Collection<T extends Comparable> 

or pass in the Comparator

Collections.sort(...) 

Comments

1

Here is an example. (I am using CompareToBuilder class from Apache for convenience, although this can be done without using it.)

import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import org.apache.commons.lang.builder.CompareToBuilder; public class Tester { boolean ascending = true; public static void main(String args[]) { Tester tester = new Tester(); tester.printValues(); } public void printValues() { List<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>(); HashMap<String, Object> map = new HashMap<String, Object>(); map.put( "actionId", new Integer(1234) ); map.put( "eventId", new Integer(21) ); map.put( "fromDate", getDate(1) ); map.put( "toDate", getDate(7) ); list.add(map); map = new HashMap<String, Object>(); map.put( "actionId", new Integer(456) ); map.put( "eventId", new Integer(11) ); map.put( "fromDate", getDate(1) ); map.put( "toDate", getDate(1) ); list.add(map); map = new HashMap<String, Object>(); map.put( "actionId", new Integer(1234) ); map.put( "eventId", new Integer(20) ); map.put( "fromDate", getDate(4) ); map.put( "toDate", getDate(16) ); list.add(map); map = new HashMap<String, Object>(); map.put( "actionId", new Integer(1234) ); map.put( "eventId", new Integer(22) ); map.put( "fromDate", getDate(8) ); map.put( "toDate", getDate(11) ); list.add(map); map = new HashMap<String, Object>(); map.put( "actionId", new Integer(1234) ); map.put( "eventId", new Integer(11) ); map.put( "fromDate", getDate(1) ); map.put( "toDate", getDate(10) ); list.add(map); map = new HashMap<String, Object>(); map.put( "actionId", new Integer(1234) ); map.put( "eventId", new Integer(11) ); map.put( "fromDate", getDate(4) ); map.put( "toDate", getDate(15) ); list.add(map); map = new HashMap<String, Object>(); map.put( "actionId", new Integer(567) ); map.put( "eventId", new Integer(12) ); map.put( "fromDate", getDate(-1) ); map.put( "toDate", getDate(1) ); list.add(map); System.out.println("\n Before Sorting \n "); for( int j = 0; j < list.size(); j++ ) System.out.println(list.get(j)); Collections.sort( list, new HashMapComparator2() ); System.out.println("\n After Sorting \n "); for( int j = 0; j < list.size(); j++ ) System.out.println(list.get(j)); } public static Date getDate(int days) { Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); cal.add(Calendar.DATE, days); return cal.getTime(); } public class HashMapComparator2 implements Comparator { public int compare(Object object1, Object object2) { if( ascending ) { return new CompareToBuilder() .append( ((HashMap)object1).get("actionId"), ((HashMap)object2).get("actionId") ) .append( ((HashMap)object2).get("eventId"), ((HashMap)object1).get("eventId") ) .toComparison(); } else { return new CompareToBuilder() .append( ((HashMap)object2).get("actionId"), ((HashMap)object1).get("actionId") ) .append( ((HashMap)object2).get("eventId"), ((HashMap)object1).get("eventId") ) .toComparison(); } } } } 

If you have a specific code that you are working on and are having issues, you can post your pseudo code and we can try to help you out!

1 Comment

Thx for your reply but i have a generic Collection this example not work for me
1

Assuming you have a list of object of type Person, using Lambda expression, you can sort the last names of users for instance by doing the following:

import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; class Person { private String firstName; private String lastName; public Person(String firstName, String lastName){ this.firstName = firstName; this.lastName = lastName; } public String getLastName(){ return this.lastName; } public String getFirstName(){ return this.firstName; } @Override public String toString(){ return "Person: "+ this.getFirstName() + " " + this.getLastName(); } } class TestSort { public static void main(String[] args){ List<Person> people = Arrays.asList( new Person("John", "Max"), new Person("Coolio", "Doe"), new Person("Judith", "Dan") ); //Making use of lambda expression to sort the collection people.sort((p1, p2)->p1.getLastName().compareTo(p2.getLastName())); //Print sorted printPeople(people); } public static void printPeople(List<Person> people){ for(Person p : people){ System.out.println(p); } } } 

Comments

0

I came across a similar problem. Had to sort a list of 3rd party class (objects).

List<ThirdPartyClass> tpc = getTpcList(...); 

ThirdPartyClass does not implement the Java Comparable interface. I found an excellent illustration from mkyong on how to approach this problem. I had to use the Comparator approach to sorting.

//Sort ThirdPartyClass based on the value of some attribute/function Collections.sort(tpc, Compare3rdPartyObjects.tpcComp); 

where the Comparator is:

public abstract class Compare3rdPartyObjects { public static Comparator<ThirdPartyClass> tpcComp = new Comparator<ThirdPartyClass>() { public int compare(ThirdPartyClass tpc1, ThirdPartyClass tpc2) { Integer tpc1Offset = compareUsing(tpc1); Integer tpc2Offset = compareUsing(tpc2); //ascending order return tpc1Offset.compareTo(tpc2Offset); } }; //Fetch the attribute value that you would like to use to compare the ThirdPartyClass instances public static Integer compareUsing(ThirdPartyClass tpc) { Integer value = tpc.getValueUsingSomeFunction(); return value; } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.