user3737020
user3737020

Reputation: 514

How to sort a list of objects

Supposing that I have a list of Test as below:

    public class Test {
    public static enum Unit {
        DAY, WEEK, MONTH, YEAR /* , DAY_TO_DAY */
    }

    private int value;
    private Unit unit;
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public Unit getUnit() {
        return unit;
    }
    public void setUnit(Unit unit) {
        this.unit = unit;
    }
}

I will have a list of Test with the below values :

3 day, 5 month, 5 day, 6 year, 6 week, 12 week,

and our expection result as below :

3 day, 5 day, 6 week , 12 week, 5 month, 6 year

Currently, I create a code as below

Collections.sort(tests, new Comparator<Test >() {
  @Override
  public int compare(Test o1, Test o2) {
    if(o1.getValue() > o2.getValue()) return 1;
    if(o1.getValue() < o2.getValue()) return -1;
    return 0;
  }

However, it only sort by value and not by Unit. The result with the above implementation is :

3 day, 5 day, 5 month, 6 week , 6 year, 12 week.

Please tell me know the way to satisfy two conditions (Unit and values) in this case. Thanks.

Upvotes: 2

Views: 103

Answers (6)

fge
fge

Reputation: 121702

Use TimeUnit to replace your Unit enum.

Your Term class could therefore have a .toMillis() method which is very simple:

public final long toMillis()
{
    return timeUnit.toMillis(value);
}

You can then just Long.compare(o1.toMillis(), o2.toMillis()) in your Comparator.

Other solutions:

  • if you use Java 8, use the new date/time API;
  • if you use Java 7- and threetenbp, use the same methods, backported;
  • if you use Java 7- and Joda Time, use Period. It is nearly equivalent to that of Java 8's/threetenbp's.

Upvotes: 1

santosh Kumar
santosh Kumar

Reputation: 1

Please use the compareto function as below:

public int compareTo(Object o) {
        Test t1 = (Test)this;
        Test t2 = (Test)o;
        if(t1.getValue()*(t1.getUnit().getValue()+1) > t2.getValue()*(t2.getUnit().getValue()+1)) return 1;
        if(t1.getValue()*(t1.getUnit().getValue()+1) < t2.getValue()*(t2.getUnit().getValue()+1)) return -1;
        return 0;
    }

and change the enum to

 public static enum Unit {
    DAY(1), WEEK(7), MONTH(31), YEAR(365) ;/* , DAY_TO_DAY */
        private final int id;
        Unit(int id) { this.id = id; }
    public int getValue() { return id; }
    }

Now you use the collection.sort(), and it will be sorted automatically

Upvotes: 0

Sumit
Sumit

Reputation: 31

You'll first have to check on the basis of Unit and then on the basis of Value in the overridden compareTo(). See here the implementation of sorting on the basis of lastname and then firstname:http://docs.oracle.com/javase/tutorial/collections/interfaces/order.html

Upvotes: 1

wassgren
wassgren

Reputation: 19201

If you simply want to compare according to your example the following code solves the problem:

Collections.sort(terms, new Comparator<Test>() {
    @Override
    public int compare(final Test o1, final Test o2) {
        int unitCompare = o1.getUnit().compareTo(o2.getUnit());
        if (unitCompare == 0) {
            return o1.getValue() - o2.getValue();
        }
        return unitCompare;
    }
});

However, this code does NOT factor in that months can have different length and the code does NOT factor in that 35 days is longer than a month.

In order to do that i suggest that the classes from the java.time package (such as java.time.Period) are used to make proper comparisons (a good trail to learn about this can be found here). If Java 8 is not an option Joda Time provides the same type of functionality.

Upvotes: 1

wgitscht
wgitscht

Reputation: 2766

If you really want to do it that way, assign your enums values like so: DAY(1), WEEK(7), MONTH(31), YEAR(365)

than multiply in your comperator Unit.getValue() * value

e.g. 4 MONTH gives you 31 * 4 = 124 is bigger than 100 DAY.

still you have the problem that teher are months with less than 31 days. recommend to convert to some common date units e.g. joda time.

Upvotes: 0

chiastic-security
chiastic-security

Reputation: 20520

You'll need to convert first into common format, and then compare. Since days are your smallest type, you should convert the two instances you're comparing into a number of days, and then compare based on that.

But you have some disambiguation to do first. How long is a month? Is it longer than 30 days, or shorter, or the same?

Upvotes: 5

Related Questions