views:

98

answers:

4

Hello EveryOne, I have a tricky question in sorting with collection.

I have a HashMap which contains some thing like the following

HashMap<String,QuoteBean> mapToSort=new HashMap<<String,QuoteBean>();

QuoteBean is basically a java bean which has properties with setter and getter methods Which looks like the following.

//class QuoteBean defination

Class QuoteBean implements Serializable{
  private BigDecimal currentPricel
  private BigDecimal  change;
  private BigDecimal TotalChange;
  private String symbol;

//with getter and setter methods  

}//end of the class

Now when i get the values from the map i usually get it like this

Collection values=mapToSort.values();//which will return all the values in the map

This values is basically a collection of QuoteBean objects. I want to sort the beans before sending it to the client. Now i can use the comparator interface and sort it .. But the problem is the sorting criteria changes frequently . I mean some time the client wants to sort with symbol,some times the client wants with change some times with total gain. The criteria changes very often. Is there a way to write the " compare " function to overload and which will satisfy all the conditions...

Is there any good way of solving this problem..

I would really appreciate if some one can reply to this topic

Thanks,

+6  A: 

Yes. Implement the java.util.Comparator interface and use the overloaded method: Collections.sort(list, comparator) (you will need to create a new List from the elements of the collection, for example new ArrayList(collection))

So you can have:

public CurrentPriceQuoteComparator implements Comparator<QuoteBean> {
    @Override
    public int compare(QuoteBean b1, QuoteBean b2) { // implement comparison }
}

public ChangeQuoteComparator implements Comparator<QuoteBean> {
    @Override
    public int compare(QuoteBean b1, QuoteBean b2) { // implement comparison }
}

And then use Collections.sort(list, ChangeQuoteComparator.INSTANCE);

Note that it is a good practice to declare a singleton instance of each comparator, instead of instantiating it each time:

public static final ChangeQuoteComparator INSTANCE = 
     new ChangeQuoteComparator();

To extend things a little more, you can define an enum with the different comparison types:

public enum ComparisonType {
   CHANGE, CURRENT_PRICE; // etc..
}

and define a Map to match each comparison type with the appropriate comparator:

private static final Map<ComparisonType, Comparator<QuoteBean>> comparators = 
      new HashMapMap<ComparisonType, Comparator<QuoteBean>>();

static {
   comparators.put(ComparisonType.CHANGE, ChangeQuoteComparator.INSTANCE);
   comparators.put(ComparisonType.CURENT_PRICE, 
           CurrentPriceQuoteComparator.INSTANCE);
}

and then let the client specify which comparison he'd like

 public List<QuoteBean> getOrdered(ComparisonType type, // other criteria) {
     List<QuoteBean> list = new ArrayList<QuoteBean>(getQuotesCollection());
     Collections.sort(list, comparators.get(type));
     return list;
 }
Bozho
+2  A: 

You can use the Comparator and create either multiple implementations, or you can use a dynamic implementation where you change the way it works by setting parameters on it.


For the multiple implementations you can take a look at @Bozho answer.

For the dynamic implementation you could do something like that :

public class DynamicComparator implements Comparator<QuoteBean> {
    public boolean compareCurrentPricel = false;
    public boolean change = false;

    //Setters for the booleans

    @Override
    public int compare(QuoteBean b1, QuoteBean b2) {
        int currentSort = 0;
        if(compareCurrentPricel && currentSort == 0){
            currentSort = compareCurrentPrice1(b1, b2);
        }
        if(change && currentSort == 0){
            currentSort = compareChange(b1, b2);
        }
    }
}

Or even better :

public class MultipleComparators<T> implements Comparator<T> {
    public List<Comparator<? super T>> comparators;

    public MultipleComparators(List<Comparator<? super T>> comparators){
        this.comparators = comparators;
    }

    @Override
    public int compare(T b1, T b2) {
        int returned = 0;
        for(Comparator<? super T> c : comparators){
            returned = c.compare(b1, b2);
            if(returned != 0){
                break;
            }
        }
        return returned;
    }
}

This way you can use any comparator you want and even multiple comparators which will be executed in the right order.

Colin Hebert
@Colin Hebert When you say multipleimplementation ..Could mind giving an example or pusdo code what do you mean by that..
@Colin Hebert could mind explaining the dynamic implementation with an example ...
@user436175, now there is an example. But after re-reading the original question, I might have misunderstood the question. I thought you wanted also compare on different elements at the same time. But still it answers the question :)
Colin Hebert
Thats perfect solution..
Thanks a lot.I apologize that my question confused you..
@user436175, no problems here :) Another thing, you should read the comments on your question, the suggestion of accepting answers will help you to be more accepted in the community ;)
Colin Hebert
public class DynamicComparator implements Comparator<QuoteBean>{}
Not sure why i get an exception called classcast exception
update your question, and post your code. Or if it has really changed create a new question.
Colin Hebert
I mean when a call like collection.sort(list,new DynamicComparator()) and the list contains and quotebean objects and not sure why i get class casr exception ..and says can not convert string to quotebean
+1  A: 

You will have to write a comparator each for every situation and depending on the client requirement you can choose the comparator.

Emil
+1  A: 

The best solution to this would be to use a beancomparator object from apache commons. You can do something like

BeanComparator comparator = new BeanComparator("currentPricel"); Collections.sort(yourlisthere, comparator);

or you can directly do a

Collections.sort(yourlisthere, new BeanComparator("currentPricel"));

mezzie