Java使用自定义字段对ArrayList进行数字和字母排序

8
public class Product implements Serializable{

    private String id;
    private String name;
    private double price ;
    private int quantity;

    public Product(String id, String name, double price, int quantity) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.quantity = quantity;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    @Override
    public String toString() {
        return "Product{" + "id=" + id + ", name=" + name + ", price=" + price + ", quantity=" + quantity + '}';
    }

我希望能够通过价格和名称对 ArrayList<Product> 进行排序。我在谷歌上搜索了很长时间,但是没有解决它。是否与 Serializable 有问题呢?

先价格,再名称? - Bohemian
2
你尝试如何对“List”进行排序? - Rohit Jain
一个带名称的案例,一个带价格的案例。不要同时翻译两个。 - haind
我不记得了。其中一些在类中使用了集合(Collections),一些实现了Comparable接口。 - haind
5个回答

28
你需要为你的目的实现 ComparableComparator 接口。可以通过阅读这些教程来了解这两者之间的区别:使用 Comparator 对自定义对象进行排序使用 Comparable 对自定义对象进行排序
如果你想要按照产品价格对你的产品进行排序,那么你需要让你的 Product 实现 Comparable 接口,如下所示。
public class Product implements Comparable<Product>{

    public int compareTo(Product other){
       // your logic here
    }

}

但是...现在我们已经实现了Comparable接口来使用它的价格对对象进行排序,那么如何使用另一种排序顺序对它们进行排序呢?我们只有一个compareTo()方法,无法在同一个类中编写单独的排序序列。这时就需要用到Comparator

使用Comparator,您可以定义多个排序序列。

假设我们想按其价格进行排序,则:

public class PriceSorter implements Comparator<Product>{

    public int compare(Product one, Product another){
        int returnVal = 0;

    if(one.getPrice() < another.getPrice()){
        returnVal =  -1;
    }else if(one.getPrice() > another.getPrice()){
        returnVal =  1;
    }else if(one.getPrice() == another.getPrice()){
        returnVal =  0;
    }
    return returnVal;
    }
}

如果您想按名称进行另一种排序,则:

public class NameSorter implements Comparator<Product>{

        public int compare(Product one, Product another){
            return one.getName().compareTo(another.getName());
        }
}

现在,当您想按价格排序时,则

Collections.sort(yourList,new PriceSorter());

如果你想按名称排序,那么

Collections.sort(yourList, new NameSorter());
第二个参数需要传入一个 Comparator 实例,这个实例确定了排序方法在对对象进行排序时要遵循的逻辑。

@morgano,两者都可以达到目的。ComparatorComparable具有一定的优势。 - Prasad Kharkar
在这种特定情况下,必须实现Comparable。如果您的对象要在对象之间进行比较,则实现Comparator,而不是要被比较的对象。 - morgano
@morgano,如果用户不被允许更改“Product”类的代码,则无法实现。使用“Comparator”,他不必更改“Product”类中的任何内容。当然,您可以使用匿名类来实现。但是,如果我们想要创建多个排序序列,则必须使用Comparator。 - Prasad Kharkar
1
有一个问题,也许我理解错了,但是原始类型 double 没有 compareTo 方法。由于 getPrice 返回的是原始类型,是否发生了自动装箱以允许使用 compareTo - Kevin Bowersox
@haind,抱歉我把代码放错了地方。我应该把它放在PriceSort里面。我已经做了相应的编辑。 - Prasad Kharkar
显示剩余6条评论

5
Product类实现Comparable接口。
public class Product implements Serializable, Comparable<Product> {

        //Ommitted constructors, fields and accessors

    //This is an ascending sort order
    @Override
    public int compareTo(Product o) {
        int result = this.name.compareToIgnoreCase(o.name);
        if(result != 0){
            return result;
        }else{
            return new Double(this.price).compareTo(new Double(o.price));
        }   
    }
}

然后,排序就像把 List 传递给 Collections.sort() 一样简单:
public static void main(String[] args) {
    Product p1 = new Product("p1", "shoes", 30.33, 20);
    Product p2 = new Product("p2", "shoes", 20.30, 20);
    Product p3 = new Product("p3", "shoes", 50.33, 20);
    Product p4 = new Product("p4", "socks", 10.50, 20);
    Product p5 = new Product("p5", "socks", 5.40, 20);
    Product p6 = new Product("p6", "socks", 2.34, 20);

    List<Product> products = Arrays.asList(p1,p2,p3,p4,p5,p6);

    System.out.println("Unsorted");
    for(Product product:products){
        System.out.println("Product: " + product.name + " Price: " + product.price);
    }

    Collections.sort(products);

    System.out.println("sorted");
    for(Product product:products){
        System.out.println("Product: " + product.name + " Price: " + product.price);
    }
}

这里是实现了Comparable接口并在main方法中提供排序示例的Product完整源代码:

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Product implements Serializable, Comparable<Product> {

    private String id;
    private String name;
    private double price;
    private int quantity;

    public Product(String id, String name, double price, int quantity) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.quantity = quantity;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    @Override
    public String toString() {
        return "Product{" + "id=" + id + ", name=" + name + ", price=" + price
                + ", quantity=" + quantity + '}';
    }

    @Override
    public int compareTo(Product o) {
        int result = this.name.compareToIgnoreCase(o.name);
        if(result != 0){
            return result;
        }else{
            return new Double(this.price).compareTo(new Double(o.price));
        }

    }

    public static void main(String[] args) {
        Product p1 = new Product("p1", "shoes", 30.33, 20);
        Product p2 = new Product("p2", "shoes", 20.30, 20);
        Product p3 = new Product("p3", "shoes", 50.33, 20);
        Product p4 = new Product("p4", "socks", 10.50, 20);
        Product p5 = new Product("p5", "socks", 5.40, 20);
        Product p6 = new Product("p6", "socks", 2.34, 20);

        List<Product> products = Arrays.asList(p1,p2,p3,p4,p5,p6);

        System.out.println("Unsorted");
        for(Product product:products){
            System.out.println("Product: " + product.name + " Price: " + product.price);
        }

        Collections.sort(products);

        System.out.println("sorted");
        for(Product product:products){
            System.out.println("Product: " + product.name + " Price: " + product.price);
        }
    }
}

@haind,你收到错误信息了吗?还是排序不如你预期的那样?如果是这样,你希望排序如何运作? - Kevin Bowersox
这是结果:20.3 30.33 50.33 2.34 5.4 10.5 - haind
@haind 这就是我理解你想要的功能。它首先按产品名称排序,然后按价格排序,都是升序排列。我假设结果应该包含产品名称? - Kevin Bowersox
那不是我想要的。我想按每种情况的价格和名称排序。现在我知道为什么它是20.3 30.33 50.33 2.34 5.4 10.5。 - haind

3

使用Comparator<Product>,这里采用匿名实现方式(适用于Java 7及更早版本):

List<Product> list;
Collections.sort(list, new Comparator<Product>() {
    public int compare(Product a, Product b) {
        if (a.getPrice() == b.getPrice())
            return a.getName().compareTo(b.getName()); 
        return a.getPrice() > b.getPrice() ? 1 : a.getPrice() < b.getPrice() ? -1 : 0
    }
});

Java 8有更简洁的方法来实现上述目标:

Collections.sort(list, Comparator.comparing(Product::getPrice).thenComparing(Product::getName));

如果这定义了您产品的“自然顺序”,考虑使Product实现Comparable<Product>并在ProductcompareTo()方法中实现它。

之前对我有用。不需要查看更新,但对于8来说似乎很好。 - VVB

1

0
据我所知,你没有这样的方法,你可以做的是:扩展Collection的子类并添加排序方法(搜索或冒泡排序等技术)。
如果你有数据库设施(更多开销) *你可以把它放在那里并使用order by *如果你正在使用JPA,只需将列表转储到实体类中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接