按属性对自定义对象的 ArrayList 进行排序

Posted

技术标签:

【中文标题】按属性对自定义对象的 ArrayList 进行排序【英文标题】:Sort ArrayList of custom Objects by property 【发布时间】:2011-02-16 14:10:29 【问题描述】:

我阅读了有关使用 Comparator 对 ArrayList 进行排序的文章,但在所有示例中,人们都使用了 compareTo,根据一些研究,这是一种字符串方法。

我想按其属性之一对自定义对象的 ArrayList 进行排序:Date 对象 (getStartDay())。通常我会通过item1.getStartDate().before(item2.getStartDate()) 比较它们,所以我想知道我是否可以写类似的东西:

public class CustomComparator 
    public boolean compare(Object object1, Object object2) 
        return object1.getStartDate().before(object2.getStartDate());
    


public class RandomName 
    ...
    Collections.sort(Database.arrayList, new CustomComparator);
    ...

【问题讨论】:

相关:***.com/questions/1814095/… Answer by @Yishai in this post 演示了使用比较器链优雅地使用枚举进行自定义排序和分组排序(多个参数)。 【参考方案1】:

由于Date 实现了Comparable,它有一个compareTo 方法,就像String 一样。

所以您的自定义 Comparator 可能如下所示:

public class CustomComparator implements Comparator<MyObject> 
    @Override
    public int compare(MyObject o1, MyObject o2) 
        return o1.getStartDate().compareTo(o2.getStartDate());
    

compare() 方法必须返回一个 int,因此您不能像您计划的那样直接返回一个 boolean

你的排序代码和你写的差不多:

Collections.sort(Database.arrayList, new CustomComparator());

如果您不需要重用比较器,那么编写所有这些的稍微短一点的方法是将其编写为内联匿名类:

Collections.sort(Database.arrayList, new Comparator<MyObject>() 
    @Override
    public int compare(MyObject o1, MyObject o2) 
        return o1.getStartDate().compareTo(o2.getStartDate());
    
);

自java-8

您现在可以通过将lambda expression 用于Comparator,以更短的形式编写最后一个示例:

Collections.sort(Database.arrayList, 
                        (o1, o2) -> o1.getStartDate().compareTo(o2.getStartDate()));

List 有一个sort(Comparator) 方法,因此您可以进一步缩短它:

Database.arrayList.sort((o1, o2) -> o1.getStartDate().compareTo(o2.getStartDate()));

这是一个常见的习惯用法,a built-in method 可以为具有Comparable 键的类生成Comparator

Database.arrayList.sort(Comparator.comparing(MyObject::getStartDate));

所有这些都是等价的形式。

【讨论】:

+1 表示它应该返回int,并且您最好使用Date#compareTo()。为什么这没有高于其他答案,这超出了我的理解。此链接也可能有用:Object Ordering Tutorial at Sun.com。 我认为最好的答案还应该包括在 Java 8 中执行此操作的正确方法。 Collections.sort(list, Comparator.comparing(MyObject::getStartDate));读起来更好,更不容易出错。很容易写 return o1.getStartDate().compareTo(o1.getStartDate()); 比较器类应该是静态的:) @Kuba 更好,使用List.sort() 此解决方案不适用于 android API 【参考方案2】:

具有自然排序顺序的类(例如 Number 类)应实现 Comparable 接口,而没有自然排序顺序的类(例如 Chair 类)应提供 Comparator(或一个匿名的 Comparator 类)。

两个例子:

public class Number implements Comparable<Number> 
    private int value;

    public Number(int value)  this.value = value; 
    public int compareTo(Number anotherInstance) 
        return this.value - anotherInstance.value;
    


public class Chair 
    private int weight;
    private int height;

    public Chair(int weight, int height) 
        this.weight = weight;
        this.height = height;
    
    /* Omitting getters and setters */

class ChairWeightComparator implements Comparator<Chair> 
    public int compare(Chair chair1, Chair chair2) 
        return chair1.getWeight() - chair2.getWeight();
    

class ChairHeightComparator implements Comparator<Chair> 
    public int compare(Chair chair1, Chair chair2) 
        return chair1.getHeight() - chair2.getHeight();
    

用法:

List<Number> numbers = new ArrayList<Number>();
...
Collections.sort(numbers);

List<Chair> chairs = new ArrayList<Chair>();
// Sort by weight:
Collections.sort(chairs, new ChairWeightComparator());
// Sort by height:
Collections.sort(chairs, new ChairHeightComparator());

// You can also create anonymous comparators;
// Sort by color:
Collections.sort(chairs, new Comparator<Chair>() 
    public int compare(Chair chair1, Chair chair2) 
        ...
    
);

【讨论】:

我试过了——但是当我想在任何其他类之外访问比较器类 ChairWeightComparator 时,我无法访问这个类(当然不是因为它不是公开的)。我是否需要在单独的文件中创建一个新的公共 ChairWeightComparator 类? - 我真的是 3 年后第一个尝试这个的人还是我错过了什么? @user387184 - 只需将其公开,并将其放入它自己的文件中(最好也是它自己的包),您就可以在项目中的任何地方使用它。无需创建额外的类! 你的意思是创建一个新文件 - 而不是一个类并输入代码:“class ChairWeightComparator implements Comparator ....”? @user387184,确切地说——但在 class 前面有关键字 public 这不适用于我的笔记本电脑。它显示 int 不能被取消引用错误。如何纠正?【参考方案3】:

要对ArrayList 进行排序,您可以使用以下代码 sn-p:

Collections.sort(studList, new Comparator<Student>()
    public int compare(Student s1, Student s2) 
        return s1.getFirstName().compareToIgnoreCase(s2.getFirstName());
    
);

【讨论】:

任何使用 lambda ***.com/questions/2784514/… 排序但为每个元素提供双倍值 这不适用于我的笔记本电脑。它显示 int 不能被取消引用错误。如何纠正?【参考方案4】:

是的,你可以。比较项目有两个选项,Comparable 接口和Comparator 接口。

这两个接口都允许不同的行为。 Comparable 允许您使对象的行为就像您刚刚描述的字符串一样(实际上,String 实现了 Comparable)。第二个,比较器,允许你做你要求做的事情。你会这样做:

Collections.sort(myArrayList, new MyComparator());

这将导致 Collections.sort 方法将比较器用于其排序机制。如果 ArrayList 中的对象实现了可比较,您可以改为执行以下操作:

Collections.sort(myArrayList);

Collections 类包含许多有用的常用工具。

【讨论】:

这不适用于我的笔记本电脑。它显示 int 不能被取消引用错误。如何纠正?【参考方案5】:

JAVA 8 lambda 表达式

Collections.sort(studList, (Student s1, Student s2) ->
        return s1.getFirstName().compareToIgnoreCase(s2.getFirstName());
);

Comparator<Student> c = (s1, s2) -> s1.firstName.compareTo(s2.firstName);
studList.sort(c)

【讨论】:

Collections.sort(studList, Comparator.comparing(Student::getFirstName)); .. 或studList.sort(Comparator.comparing(Student::getFirstName)); 在您的情况下,排序顺序将始终为升序。在我的示例中,我也处理了排序顺序。谢谢先生们。【参考方案6】:

在 Java 8 中,您可以为比较器使用方法引用:

import static java.util.Comparator.comparing;

Collections.sort(list, comparing(MyObject::getStartDate));

【讨论】:

@user387184 不幸的是android不支持Java 8,虽然可能有workaround(我没有测试过)。【参考方案7】:

由于技术每天都在出现,答案会随着时间而改变。我看了一下 LambdaJ,看起来很有趣。

您可以尝试使用 LambdaJ 解决这些任务。你可以在这里找到它:http://code.google.com/p/lambdaj/

这里有一个例子:

排序迭代

List<Person> sortedByAgePersons = new ArrayList<Person>(persons);
Collections.sort(sortedByAgePersons, new Comparator<Person>() 
        public int compare(Person p1, Person p2) 
           return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
        
);

使用 lambda 排序

List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge()); 

当然,有这种美感对性能有影响(平均2倍),但是你能找到更可读的代码吗?

【讨论】:

排序但为每个元素提供双倍值如何避免它 @Sam,它不应该......它按预期工作。除非您正在使用带有错误的新版本,否则我建议您将其发布在论坛中。无论如何,这个答案是在 java 8 之前发布的,如果你使用它,那么它会比使用 lambdaj 好得多 我不得不删除 foreach 循环中的偶数项,否则它会给我每个内容的两倍。【参考方案8】:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;

public class test 

public static class Person 
    public String name;
    public int id;
    public Date hireDate;

    public Person(String iname, int iid, Date ihireDate) 
        name = iname;
        id = iid;
        hireDate = ihireDate;
    

    public String toString() 
        return name + " " + id + " " + hireDate.toString();
    

    // Comparator
    public static class CompId implements Comparator<Person> 
        @Override
        public int compare(Person arg0, Person arg1) 
            return arg0.id - arg1.id;
        
    

    public static class CompDate implements Comparator<Person> 
        private int mod = 1;
        public CompDate(boolean desc) 
            if (desc) mod =-1;
        
        @Override
        public int compare(Person arg0, Person arg1) 
            return mod*arg0.hireDate.compareTo(arg1.hireDate);
        
    


public static void main(String[] args) 
    // TODO Auto-generated method stub
    SimpleDateFormat df = new SimpleDateFormat("mm-dd-yyyy");
    ArrayList<Person> people;
    people = new ArrayList<Person>();
    try 
        people.add(new Person("Joe", 92422, df.parse("12-12-2010")));
        people.add(new Person("Joef", 24122, df.parse("1-12-2010")));
        people.add(new Person("Joee", 24922, df.parse("12-2-2010")));
     catch (ParseException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
    

    Collections.sort(people, new Person.CompId());
    System.out.println("BY ID");
    for (Person p : people) 
        System.out.println(p.toString());
    

    Collections.sort(people, new Person.CompDate(false));
    System.out.println("BY Date asc");
    for (Person p : people) 
        System.out.println(p.toString());
    
    Collections.sort(people, new Person.CompDate(true));
    System.out.println("BY Date desc");
    for (Person p : people) 
        System.out.println(p.toString());
    




【讨论】:

欢迎来到***。这个问题前段时间已经回答过了。在恢复旧线程之前,请确保您的回复为线程添加了一些重要的内容。 请在您的答案中添加解释。 编译运行即可。代码是注释和解释。【参考方案9】:

使用 JAVA 8 最简单的方法是英文字母排序

类实现

public class NewspaperClass implements Comparable<NewspaperClass>
   public String name;

   @Override
   public int compareTo(NewspaperClass another) 
      return name.compareTo(another.name);
   

排序

  Collections.sort(Your List);

如果要对包含非英文字符的字母进行排序,可以使用 Locale... 下面的代码使用土耳其字符排序...

类实现

public class NewspaperClass implements Comparator<NewspaperClass> 
   public String name;
   public Boolean isUserNewspaper=false;
   private Collator trCollator = Collator.getInstance(new Locale("tr_TR"));



   @Override
   public int compare(NewspaperClass lhs, NewspaperClass rhs) 
      trCollator.setStrength(Collator.PRIMARY);
      return trCollator.compare(lhs.name,rhs.name);
   

排序

Collections.sort(your array list,new NewspaperClass());

【讨论】:

【参考方案10】:

函数和方法参考

Collections.sort 方法可以使用您传递的ComparatorList 进行排序。 Comparator 可以使用 Comparator.comparing 方法实现,您可以将 method reference 作为必要的 Function 传递。幸运的是,实际代码比这个描述要简单得多。

对于 Java 8:

Collections.sort(list, comparing(ClassName::getName));

Collections.sort(list, comparing(ClassName::getName).reversed());

另一种方法是

Collections.sort(list, comparing(ClassName::getName, Comparator.nullsLast(Comparator.naturalOrder())));

【讨论】:

调用需要 API 级别 24【参考方案11】:

您可以使用 java 8 进行排序

yourList.sort(Comparator.comparing(Classname::getName));

or

yourList.stream().forEach(a -> a.getBObjects().sort(Comparator.comparing(Classname::getValue)));

【讨论】:

【参考方案12】:

Java 8 开始,我们不必直接使用Collections.sort()List 接口有一个默认的sort() 方法:

List<User> users = Arrays.asList(user1,user2,user3);
users.sort( (u1, u2) ->  
return u1.getFirstName.compareTo(u2.getFirstName());); 

见http://visvv.blogspot.in/2016/01/sorting-objects-in-java-8.html

【讨论】:

【参考方案13】:

Java 8 Lambda 缩短了排序。

Collections.sort(stdList, (o1, o2) -> o1.getName().compareTo(o2.getName()));

【讨论】:

Collections.sort(stdList, Comparator.comparing(SomeClass::getName));【参考方案14】:

您可以使用Bean Comparator 对自定义类中的任何属性进行排序。

【讨论】:

【参考方案15】:

是的,这是可能的,例如在 this answer 中,我按 IndexValue 类的属性 v 进行排序

    // Sorting by property v using a custom comparator.
    Arrays.sort( array, new Comparator<IndexValue>()
        public int compare( IndexValue a, IndexValue b )
            return a.v - b.v;
        
    );

如果你注意到这里我正在创建一个 匿名内部类(这是用于闭包的 Java)并将其直接传递给 Arrays 类的 sort 方法

您的对象也可以实现Comparable(这就是 String 和 Java 中的大多数核心库所做的),但这将定义它自身的类的“自然排序顺序”,并且不允许您插入新的类.

【讨论】:

...但是你可以用Comparator 覆盖它:)【参考方案16】:

我发现大多数(如果不是全部)这些答案都依赖于底层类(对象)来实现可比较或具有辅助可比较接口。

不是我的解决方案!以下代码可让您通过了解对象的字符串名称来比较对象的字段。您可以轻松地将其修改为不使用该名称,但随后您需要公开它或构造您想要比较的对象之一。

Collections.sort(anArrayListOfSomeObjectPerhapsUsersOrSomething, new ReflectiveComparator(). new ListComparator("name"));

public class ReflectiveComparator 
    public class FieldComparator implements Comparator<Object> 
        private String fieldName;

        public FieldComparator(String fieldName)
            this.fieldName = fieldName;
        

        @SuppressWarnings( "unchecked", "rawtypes" )
        @Override
        public int compare(Object object1, Object object2) 
            try 
                Field field = object1.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);

                Comparable object1FieldValue = (Comparable) field.get(object1);
                Comparable object2FieldValue = (Comparable) field.get(object2);

                return object1FieldValue.compareTo(object2FieldValue);
            catch (Exception e)

            return 0;
        
    

    public class ListComparator implements Comparator<Object> 
        private String fieldName;

        public ListComparator(String fieldName) 
            this.fieldName = fieldName;
        

        @SuppressWarnings( "unchecked", "rawtypes" )
        @Override
        public int compare(Object object1, Object object2) 
            try 
                Field field = object1.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                Comparable o1FieldValue = (Comparable) field.get(object1);
                Comparable o2FieldValue = (Comparable) field.get(object2);

                if (o1FieldValue == null) return -1;
                if (o2FieldValue == null) return 1;
                return o1FieldValue.compareTo(o2FieldValue);
             catch (NoSuchFieldException e) 
                throw new IllegalStateException("Field doesn't exist", e);
             catch (IllegalAccessException e) 
                throw new IllegalStateException("Field inaccessible", e);
            
        
    

【讨论】:

【参考方案17】:

你可以试试番石榴Ordering:

Function<Item, Date> getStartDate = new Function<Item, Date>() 
    public Date apply(Item item) 
        return item.getStartDate();
    
;

List<Item> orderedItems = Ordering.natural().onResultOf(getStartDate).
                          sortedCopy(items);

【讨论】:

【参考方案18】:

您的 customComparator 类必须实现 java.util.Comparator 才能使用。 它还必须覆盖 compare() AND equals()

compare() 必须回答这个问题:对象 1 是否小于、等于或大于对象 2?

完整文档:http://java.sun.com/j2se/1.5.0/docs/api/java/util/Comparator.html

【讨论】:

【参考方案19】:

此代码 sn-ps 可能很有用。如果要对对象进行排序 就我而言,我想按 VolumeName 排序:

public List<Volume> getSortedVolumes() throws SystemException 
    List<Volume> volumes = VolumeLocalServiceUtil.getAllVolumes();
    Collections.sort(volumes, new Comparator<Volume>() 
        public int compare(Volume o1, Volume o2) 
            Volume p1 = (Volume) o1;
            Volume p2 = (Volume) o2;
            return p1.getVolumeName().compareToIgnoreCase(
                    p2.getVolumeName());
        
    );
    return volumes;

这行得通。我在我的jsp中使用它。

【讨论】:

【参考方案20】:

使用这个库here,您可以对多个列上的自定义对象列表进行排序。该库使用 8.0 版功能。那里也有样品。这是一个示例

SortKeys sortKeys = new SortKeys();
sortKeys.addField("firstName")
            .addField("age", true); // This (true) will sort the age descending

// Other ways to specify a property to the sorter are
//      .addField("lastName", String.class);
//      .addField("dob", Date.class, true);

// Instantiate a ListSorter
ListSorter listSorter = new ListSorter();

// Pass the data to sort (listToSort) and the "by keys" to sort (sortKeys)
List sortedList = (List<Person>) listSorter.sortList(listToSort, sortKeys);

【讨论】:

【参考方案21】:

您可以查看 2016 年在德国斯图加特举行的 Java 论坛上的 presentation。

只有少数幻灯片使用德语,99% 的内容是“基于英语的”Java 源代码;喜欢

someCollection.sort(
  OurCustomComparator
    .comparing(Person::getName)
    .thenComparing(Person::getId)
);

OurCustomComparator 使用默认方法(和其他有趣的想法)。如图所示,导致代码非常简洁,可以选择一些 getter 方法进行排序;和排序标准的超级简单链接(或反转)。

如果您对 java8 感兴趣,您会发现那里有很多资料可以帮助您入门。

【讨论】:

【参考方案22】:

自 1.8 以来的新功能是 List.sort() 方法,而不是使用 Collection.sort() 所以你直接调用 mylistcontainer.sort()

这是一个演示 List.sort() 功能的代码 sn-p:

List<Fruit> fruits = new ArrayList<Fruit>();
fruits.add(new Fruit("Kiwi","green",40));
fruits.add(new Fruit("Banana","yellow",100));
fruits.add(new Fruit("Apple","mixed green,red",120));
fruits.add(new Fruit("Cherry","red",10));

// a) using an existing compareto() method
fruits.sort((Fruit f1,Fruit f2) -> f1.getFruitName().compareTo(f2.getFruitName()));
System.out.println("Using String.compareTo(): " + fruits);
//Using String.compareTo(): [Apple is: mixed green,red, Banana is: yellow, Cherry is: red, Kiwi is: green]

// b) Using a comparable class
fruits.sort((Fruit f1,Fruit f2) -> f1.compareTo(f2));  
System.out.println("Using a Comparable Fruit class (sort by color): " + fruits);
// Using a Comparable Fruit class (sort by color): [Kiwi is green, Apple is: mixed green,red, Cherry is: red, Banana is: yellow]

水果类是:

public class Fruit implements Comparable<Fruit>

    private String name;
    private String color;
    private int quantity;

    public Fruit(String name,String color,int quantity)
     this.name = name; this.color = color; this.quantity = quantity; 

    public String getFruitName()  return name;         
    public String getColor()  return color;   
    public int getQuantity()  return quantity; 

    @Override public final int compareTo(Fruit f) // sorting the color
    
        return this.color.compareTo(f.color);
         
    @Override public String toString()
       
        return (name + " is: " + color);
    
 // end of Fruit class   

【讨论】:

【参考方案23】:

我更喜欢这个过程:

public class SortUtil
    
    public static <T> List<T> sort(List<T> list, String sortByProperty)
    
            Collections.sort(list, new BeanComparator(sortByProperty));
            return list;
    


List<T> sortedList = SortUtil<T>.sort(unsortedList, "startDate");

如果您的对象列表有一个名为startDate 的属性,则您会一遍又一遍地调用use this。你甚至可以链接它们startDate.time

这要求您的对象是Comparable,这意味着您需要compareToequalshashCode 实现。

是的,它可以更快...但是现在您不必为每种类型的排序创建一个新的比较器。如果您可以节省开发时间并放弃运行时,您可能会选择这个。

【讨论】:

1,这个答案是在 2 小时前给出的,并提供了工作代码。无需重新发布相同的解决方案并使论坛变得混乱,尤其是因为 BeanComparator 不是标准类,因此如果发布者不知道您在说什么,它就不是真正的解决方案。如果您喜欢最初的建议,可以点赞并添加评论。【参考方案24】:

使用 java-8 流 api,您可以按以下方式对 ArrayList 进行排序:

 Comparator<Person> birthdayComparator = Comparator.comparing(Person::getBirthday);
 List<Person> sortedList = list.stream().sorted(birthdayComparator).collect(toList());

【讨论】:

【参考方案25】:

如果您使用 Java 8 或更早版本,这是最好的解决方案。

Collections.sort(studentList, Comparator.comparing(Student::getCgpa).reversed().thenComparing(Student:: getFname).thenComparing(Student::getId));

在这种情况下,它将首先使用 'getCgpa' 进行排序,而对于第二部分,它将使用 getFname 和 getId 进行排序。这是 pojo 类的字段。

【讨论】:

【参考方案26】:

使用Java 8 使用Comparator可以在一行中定义Comparator.comparing()

使用以下任一方式:

选项 1:

listToBeSorted.sort(Comparator.comparing(CustomObject::getStartDate));

选项 2:

Collections.sort(listToBeSorted, Comparator.comparing(CustomObject::getStartDate));

【讨论】:

似乎与 3 年前的 this Answer 重复。 不完全是,这里只有选项 2 类似于上述答案中的选项 1。我觉得如果两个不同的答案是对同一个问题的答案,它们至少会有一些相似之处。【参考方案27】:

您的自定义类可以实现“Comparable”接口,这需要实现 CompareTo 方法。在 CompareTo 方法中,您可以定义一个对象小于或大于另一个对象的含义。所以在你的例子中,它可能看起来像这样:

public class MyCustomClass implements Comparable<MyCustomClass>

.......

 @Override
public int compareTo(MyCustomClass a) 
    if(this.getStartDate().before(a.getStartDate()))
        return -1;
    else if(a.getStartDate().before(this.getStartDate()))
        return 1;
    else 
        return 0;
    

负数表示this小于被比较的对象。正数表示 this 大于比较对象,零表示对象相等。

然后您可以使用 collections.sort(myList) 对列表进行排序,而无需输入比较器。如果您使用已排序的集合数据结构(如 TreeSet 或 TreeMap),此方法还具有自动排序的优点。

如果您想了解更多关于 Comparable 接口的信息,可以查看这篇文章(披露:我是作者;)) https://nullbeans.com/the-java-comparable-interface-automatic-sort-of-collections/

【讨论】:

【参考方案28】:

如果您只有要排序的(嵌套)属性的字符串属性路径,也可以使用 Springs PropertyComparator:

List<SomeObject> list = ...;
PropertyComparator<HitWithInfo> propertyComparator = new PropertyComparator<>(
    "property.nested.myProperty", false, true);
list.sort(propertyComparator);

缺点是,这个比较器会默默地忽略不存在或不可访问的属性,并将其作为 null 值进行比较。这意味着,您应该仔细测试这样的比较器或以某种方式验证属性路径的存在。

【讨论】:

【参考方案29】:

我在互联网上尝试了很多不同的解决方案,但对我有用的解决方案可以在下面的链接中找到。

https://www.java67.com/2017/07/how-to-sort-arraylist-of-objects-using.html

【讨论】:

以上是关于按属性对自定义对象的 ArrayList 进行排序的主要内容,如果未能解决你的问题,请参考以下文章

如何按对象属性对 ArrayList 进行排序? [复制]

Swift 2.0 按属性对对象数组进行排序

按对象属性对对象的 ArrayList 进行排序

在Java中按属性值对对象ArrayList进行排序

Java:通用的排序工具类,能够对自定义对象,针对不同的属性(字段),实现排序(正序倒序)

如何用java对excel进行自定义排序?