按属性排序自定义对象列表

我读过关于使用比较器对ArrayList进行排序的文章,但在所有示例中,人们都使用了compareTo,根据一些研究,它是Strings的一种方法。

我想通过它们的属性之一对自定义对象的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);...}
1290676 次浏览

可以。比较项有两个选项,可比界面和比较器界面。

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

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

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

Collections.sort(myArrayList);

收藏类包含许多这些有用的常用工具。

由于#0实现了#1,它有一个compareTo方法,就像String一样。

所以你的自定义#0可能看起来像这样:

public class CustomComparator implements Comparator<MyObject> {@Overridepublic 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>() {@Overridepublic int compare(MyObject o1, MyObject o2) {return o1.getStartDate().compareTo(o2.getStartDate());}});

您现在可以通过使用lambda表达式作为Comparator以较短的形式编写最后一个示例:

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

List有一个#1方法,所以你可以进一步缩短:

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

这是一个非常常见的习惯用法,一个内置方法为具有Comparable键的类生成Comparator

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

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

自定义比较器类必须实现java.util.比较器才能使用。它还必须覆盖比较()AND equals()

比较()必须回答这个问题:对象1小于、等于还是大于对象2?

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

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

是的,这是可能的,例如在这个答案中,我按类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)并将其直接传递给类Arrayssort方法

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

具有自然排序顺序的类(例如类编号)应该实现比较接口,而没有自然排序顺序的类(例如类主席)应该提供一个比较器(或匿名比较器类)。

两个例子:

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) {...}});

我更喜欢这个过程:

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实现。

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

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();}
// Comparatorpublic static class CompId implements Comparator<Person> {@Overridepublic 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;}@Overridepublic int compare(Person arg0, Person arg1) {return mod*arg0.hireDate.compareTo(arg1.hireDate);}}}
public static void main(String[] args) {// TODO Auto-generated method stubSimpleDateFormat 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 blocke.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());}
}
}

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

不是我的解决方案!下面的代码允许你通过知道它们的字符串名称来比较对象的字段。你可以很容易地修改它以不使用该名称,但随后你需要公开它或构造一个要比较的对象。

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" })@Overridepublic 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" })@Overridepublic 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);}}}}

要对ArrayList进行排序,您可以使用以下代码片段:

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

这段代码片段可能很有用。如果你想对对象进行排序在我的情况下,我想按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中使用它。

您可以尝试Guava订购

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);

由于技术每天都在出现,答案会随着时间的推移而改变。我看了看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倍),但你能找到更具可读性的代码吗?

使用Java8,您可以为比较器使用方法引用:

import static java.util.Comparator.comparing;
Collections.sort(list, comparing(MyObject::getStartDate));

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)

Java8 Lambda缩短了排序。

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

使用此库这里,您可以对多列上的自定义对象列表进行排序。该库使用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 ListSorterListSorter listSorter = new ListSorter();
// Pass the data to sort (listToSort) and the "by keys" to sort (sortKeys)List sortedList = (List<Person>) listSorter.sortList(listToSort, sortKeys);

功能&方法参考

#0方法可以使用您传递的#2#1进行排序。Comparator可以使用#4方法实现,您可以将List0作为必要的List1传递。幸运的是,实际代码比此描述简单得多。

Java8:

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

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

另一种方法是

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

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

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

类实现

public class NewspaperClass implements Comparable<NewspaperClass>{public String name;
@Overridepublic int compareTo(NewspaperClass another) {return name.compareTo(another.name);}}

排序

  Collections.sort(Your List);

如果您想对包含非英语字符的字母表进行排序,您可以使用区域设置…下面的代码使用土耳其字符排序…

类实现

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


@Overridepublic int compare(NewspaperClass lhs, NewspaperClass rhs) {trCollator.setStrength(Collator.PRIMARY);return trCollator.compare(lhs.name,rhs.name);}}

排序

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

您可以使用Java 8进行排序

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

您可以在2016年德国斯图加特的Java论坛上查看此介绍

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

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

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

如果你对java8感兴趣,你会在那里找到很多材料来帮助你入门。

新的,因为1.8是一个List.sort()方法,而不是使用Collection.sort()所以你直接调用mylistcontainer.sort()

下面的代码片段演示了List.sort()特性:

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() methodfruits.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 classfruits.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

使用Java8 use可以使用Comparator.comparing()在一行中定义Comparator

使用以下任何一种方式:

备选案文1:

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

备选案文2:

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

你的自定义类可以实现“可比较”接口,这需要CompareTo方法的实现。然后,在CompareTo方法中,你可以定义一个对象是另一个对象的小于或大于意味着什么。所以在你的例子中,它看起来像这样:

public class MyCustomClass implements Comparable<MyCustomClass>{

……

 @Overridepublic int compareTo(MyCustomClass a) {if(this.getStartDate().before(a.getStartDate())){return -1;}else if(a.getStartDate().before(this.getStartDate())){return 1;}else {return 0;}}

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

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

你可以查看这篇文章,如果你想阅读更多关于比较界面(披露:我是作者;))https://nullbeans.com/the-java-comparable-interface-automatic-sort-of-collections/

如果您只有要排序的(嵌套)属性的String属性路径,您也可以使用Springs属性比较器

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

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

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

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

我已经尝试了很多不同的解决方案在互联网上,但解决方案,为我工作是在下面的链接。

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

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

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

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