简体   繁体   中英

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.

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?

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.

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

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.

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

eg 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 eg joda time.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM