Java 按属性对自定义对象的 ArrayList 进行排序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2784514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sort ArrayList of custom Objects by property
提问by Samuel
I read about sorting ArrayLists using a Comparator but in all of the examples people used compareTo
which according to some research is a method for Strings.
我读过关于使用 Comparator 对 ArrayLists 进行排序的内容,但在人们使用的所有示例中compareTo
,根据一些研究,这是一种用于字符串的方法。
I wanted to sort an ArrayList of custom objects by one of their properties: a Date object
(getStartDay()
). Normally I compare them by item1.getStartDate().before(item2.getStartDate())
so I was wondering whether I could write something like:
我想通过自定义对象的属性之一对自定义对象的 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);
...
}
采纳答案by Michael Myers
Since Date
implements Comparable
, it has a compareTo
method just like String
does.
由于Date
implements Comparable
,它有一个和compareTo
do 一样的方法String
。
So your custom Comparator
could look like this:
因此,您的自定义Comparator
可能如下所示:
public class CustomComparator implements Comparator<MyObject> {
@Override
public int compare(MyObject o1, MyObject o2) {
return o1.getStartDate().compareTo(o2.getStartDate());
}
}
The compare()
method must return an int
, so you couldn't directly return a boolean
like you were planning to anyway.
该compare()
方法必须返回 an int
,因此boolean
无论如何您都无法像计划中那样直接返回 a 。
Your sorting code would be just about like you wrote:
你的排序代码就像你写的一样:
Collections.sort(Database.arrayList, new CustomComparator());
A slightly shorter way to write all this, if you don't need to reuse your comparator, is to write it as an inline anonymous class:
如果您不需要重用比较器,则编写所有这些的一种略短的方法是将其编写为内联匿名类:
Collections.sort(Database.arrayList, new Comparator<MyObject>() {
@Override
public int compare(MyObject o1, MyObject o2) {
return o1.getStartDate().compareTo(o2.getStartDate());
}
});
Since java-8
从java-8
You can now write the last example in a shorter form by using a lambda expressionfor the Comparator
:
您现在可以通过对 使用lambda 表达式以更短的形式编写最后一个示例Comparator
:
Collections.sort(Database.arrayList,
(o1, o2) -> o1.getStartDate().compareTo(o2.getStartDate()));
And List
has a sort(Comparator)
method, so you can shorten this even further:
并且List
有一个sort(Comparator)
方法,所以你可以进一步缩短它:
Database.arrayList.sort((o1, o2) -> o1.getStartDate().compareTo(o2.getStartDate()));
This is such a common idiom that there's a built-in methodto generate a Comparator
for a class with a Comparable
key:
这是一个非常常见的习惯用法,以至于有一个内置方法可以Comparator
为带有Comparable
键的类生成 a :
Database.arrayList.sort(Comparator.comparing(MyObject::getStartDate));
All of these are equivalent forms.
所有这些都是等价形式。
回答by aperkins
Yes, you can. There are two options with comparing items, the Comparableinterface, and the Comparatorinterface.
是的你可以。比较项有两个选项,Comparable接口和Comparator接口。
Both of these interfaces allow for different behavior. Comparable allows you to make the object act like you just described Strings (in fact, String implements Comparable). The second, Comparator, allows you to do what you are asking to do. You would do it like this:
这两个接口都允许不同的行为。Comparable 允许您使对象表现得像您刚刚描述的字符串(实际上,字符串实现了 Comparable)。第二个是 Comparator,它允许你做你要求做的事情。你会这样做:
Collections.sort(myArrayList, new MyComparator());
That will cause the Collections.sort method to use your comparator for it's sorting mechanism. If the objects in the ArrayList implement comparable, you can instead do something like this:
这将导致 Collections.sort 方法将您的比较器用于它的排序机制。如果 ArrayList 中的对象实现了可比性,您可以改为执行以下操作:
Collections.sort(myArrayList);
The Collectionsclass contains a number of these useful, common tools.
该集合类包含了一些这些有用的,常用工具。
回答by Vinny
your customComparator class must implement java.util.Comparator in order to be used. it must also overide compare() AND equals()
您的 customComparator 类必须实现 java.util.Comparator 才能使用。它还必须覆盖 compare() AND equals()
compare() must answer the question: Is object 1 less than, equal to or greater than object 2?
compare() 必须回答这个问题:对象 1 是否小于、等于或大于对象 2?
full docs: http://java.sun.com/j2se/1.5.0/docs/api/java/util/Comparator.html
完整文档:http: //java.sun.com/j2se/1.5.0/docs/api/java/util/Comparator.html
回答by camickr
You can use the Bean Comparatorto sort on any property in your custom class.
您可以使用Bean Comparator对自定义类中的任何属性进行排序。
回答by OscarRyz
Yes, that's possible for instance in this answerI sort by the property v
of the class IndexValue
是的,这是可能的,例如在这个答案中我按v
类的属性排序IndexValue
// 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;
}
});
If you notice here I'm creating a anonymous inner class( which is the Java for closures ) and passing it directly to the sort
method of the class Arrays
如果您注意到这里我正在创建一个匿名内部类(它是用于闭包的 Java)并将其直接传递给sort
类的方法Arrays
Your object may also implement Comparable
( that's what String and most of the core libraries in Java does ) but that would define the "natural sort order" of the class it self, and doesn't let you plug new ones.
您的对象也可能实现Comparable
(这就是 String 和 Java 中的大多数核心库所做的),但这将定义它自己的类的“自然排序顺序”,并且不允许您插入新的类。
回答by Bj?rn
Classes that has a natural sort order (a class Number, as an example) should implement the Comparable interface, whilst classes that has no natural sort order (a class Chair, as an example) should be provided with a Comparator (or an anonymous Comparator class).
具有自然排序顺序的类(例如 Number 类)应该实现 Comparable 接口,而没有自然排序顺序的类(例如类 Chair)应该提供一个 Comparator(或匿名 Comparator班级)。
Two examples:
两个例子:
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();
}
}
Usage:
用法:
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) {
...
}
});
回答by DDus
I prefer this process:
我更喜欢这个过程:
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");
If you list of objects has a property called startDate
, you call use this over and over. You can even chain them startDate.time
.
如果你的对象列表有一个名为 的属性startDate
,你会一遍又一遍地调用 use this 。您甚至可以将它们链接起来startDate.time
。
This requires your object to be Comparable
which means you need a compareTo
, equals
, and hashCode
implementation.
这需要你的对象是Comparable
你需要哪些手段compareTo
,equals
以及hashCode
实现。
Yes, it could be faster... But now you don't have to make a new Comparator for each type of sort. If you can save on dev time and give up on runtime, you might go with this one.
是的,它可能会更快……但是现在您不必为每种类型都创建一个新的比较器。如果您可以节省开发时间并放弃运行时,您可能会选择这个。
回答by CharlesW
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());
}
}
}
回答by Kevin Parker
I found most if not all of these answers rely on the underlying class (Object) to implement comparable or to have a helper comparable interface.
我发现大多数(如果不是全部)这些答案都依赖于底层类 (Object) 来实现可比较或具有辅助可比较接口。
Not with my solution! The following code lets you compare object's field by knowing their string name. You could easily modify it not to use the name, but then you need to expose it or construct one of the Objects you want to compare against.
不是我的解决方案!以下代码可让您通过了解对象的字符串名称来比较对象的字段。您可以轻松修改它以不使用该名称,但随后您需要公开它或构建您要与之比较的对象之一。
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);
}
}
}
}
回答by Kevin Parker
For sorting an ArrayList
you could use the following code snippet:
对于排序,ArrayList
您可以使用以下代码片段:
Collections.sort(studList, new Comparator<Student>(){
public int compare(Student s1, Student s2) {
return s1.getFirstName().compareToIgnoreCase(s2.getFirstName());
}
});