Java sort object by list type property

2019-03-03 14:54发布

问题:

I have the following objects:

public class Shipping {
    String name;
    List<Method> methods;
}

public class Method {
    String serviceType;
    String cost;
}

I have:

List<Shipping> shippings;

I would like to sort the shipping by the method that returned the cheapest cost.

Example:

shipping: "Josh" with 2 methods: "Premium","5" and "Basic","3"
shopping: "Nash" with 2 methods: "Prem", "7" and "Base","2"

will sort it like this:

shopping: "Nash" with 2 methods: "Base","2" and "Prem", "7"
shopping: "Josh" with 2 methods: "Basic","3" and "Premium","5"

I need it to return the method that has the cheapest method cost as the first one, while sorting also the methods to have the cheapest one first.

What's the best way to do it? I am using Java 8 if it has a better solution, and have guava library

EDIT: cost is a float number. I need to leave it as String as it's an object that I pass to REST api and wouldn't like client side to parse it.

回答1:

We will assume all the shippings have at least 1 method. So you want the methods of the shippings to be sorted by cost. So let's do that:

shippings.forEach(shipping -> {
    shipping.getMethods().sort(Comparator.comparing(Method::getCost));
});

Then you want the list of shippings to be sorted by the lowest cost of their methods. The lowest cost is the cost of the first method, since they're now sorted:

shippings.sort(Comparator.comparing(shipping -> shipping.getMethods().get(0).getCost()));

Note that this assumes that you want the costs to be compared lexicographically. If, as I suspect, the cost is in fact a number, then it should be stored as such in the Method class, and not as a String. So make it an Integer or a BigDecimal, or whatever the appropriate type is.



回答2:

You need either a comparator or implement Comparable for Method class like:

public class Method implements Comparable<Method> {
    public int compareTo(Method thatMethod) {
        return Integer.compare(Integer.parseInt(this.cost), Integer.parseInt(thatMethod.getCost()));//if you need name then you could do this.cost.compareTo(thatMethod.getServiceType()); assuming serviceType can never be null 
    }
}

And then sort your list like:

Collections.sort(methods);


回答3:

You can define new Comparator to define your sort criteria like this:

Comparator<Shipping> shippingComparator = new Comparator<Shipping>{
public int compare(Shipping obj1, Shipping obj2) {
    //your rules for comparing Shipping1, Shipping 2 goes here
    //return -1 when obj1 should be before obj2
    //return 1 when obj1 should be after obj2
    //return 0 when obj1 is equal to obj2 and relative position doesnt matter
} 

Then use this comparator to sort your List:

ArrayList<Shipping> shippings;
//populate List
Collections.sort(shippings, shippingComparator );


回答4:

You can first sort the methods field of each Shipping instance in your shippings list, then sort the shippings list by the first element of each instance's methods list:

for (Shipping shipping : shippings)
    shipping.methods.sort((m1, m2) -> Integer.compare(m1.cost, m2.cost));

shippings.sort((s1, s2) -> 
  Integer.compare(s1.methods.get(0).cost, s2.methods.get(0).cost));

You might have to do a little extra work converting the costs to integers, but the overall idea is the same.



回答5:

I would recommend that you read Java's ordering tutorial. Your requirements seem to indicate that you want to sort each Shipping instance by its Method, and somewhere else you want to sort a collection of Shipping instances that you want sorted alphabetically, but its not completely clear from what you've written.

In any case, this is straight forward to do once you read the tutorial. In summary, you can do this with a Comparator or by implementing Comparable, and simply invoking Collections.sort(...) on your dataset.