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

1282

我了解到可以使用Comparator对ArrayList进行排序,但在所有示例中,人们都使用了compareTo方法,这是一种针对字符串的方法。

我想要通过一个自定义对象属性(Date类型的getStartDay()方法)来对ArrayList进行排序。通常,我会使用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);
    ...
}

4
相关链接:https://dev59.com/NXI-5IYBdhLWcg3whYsr - BalusC
2
此帖中@Yishai的回答展示了枚举在自定义排序和分组排序(多个参数)中的优雅使用,利用比较器链接。 - gunalmel
29个回答

3
这段代码可能很有用。如果你想对一个对象进行排序,比如我想按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中使用它。


3

3
你可以查看这个2016年德国斯图加特Java论坛上的演示文稿。只有几张幻灯片使用了德语,99%的内容是基于英语的Java源代码。链接如下:presentation
someCollection.sort(
  OurCustomComparator
    .comparing(Person::getName)
    .thenComparing(Person::getId)
);

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

如果你喜欢Java8,你会找到很多资料来帮助你入门。


FYI,演示文稿链接已失效。 - AJW
@AJW 谢谢,是的,我之所以在这里添加代码是有原因的...我假设链接总有一天会失效。只是不知道我还能从哪里提供那个文件。 - GhostCat

2
使用Java 8 Stream API,您可以按以下方式对ArrayList进行排序:
 Comparator<Person> birthdayComparator = Comparator.comparing(Person::getBirthday);
 List<Person> sortedList = list.stream().sorted(birthdayComparator).collect(toList());

1

我更喜欢这个过程:

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的属性,你可以一遍又一遍地调用它。你甚至可以将它们链接起来startDate.time
这需要你的对象是可比较的,这意味着你需要实现compareToequalshashCode
是的,它可能会更快...但现在你不必为每种类型的排序制作新的比较器。如果你可以节省开发时间并放弃运行时,你可以选择这个方法。

3
这个答案在2小时前已经给出,并提供了可工作的代码。没有必要重新发布相同的解决方案并且弄乱论坛,特别是由于BeanComparator不是一个标准类,如果发布者不知道你在说什么,那么这并不是一个真正的解决方案。如果你喜欢原始建议,可以给它点赞,并在需要时添加评论。 - camickr

0

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

可以使用以下任何一种方式:

选项1:

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

选项2:

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

1
似乎是3年前的这个答案的重复。 - Basil Bourque
1
不完全一样,这里的选项2只是与提到的答案中的选项1相似。如果两个不同的答案是针对同一个问题的回答,那么它们至少可以有一些相似之处。 - Sahil Chhabra

0

您的自定义类可以实现“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;
    }
}

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

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

如果您想阅读更多关于Comparable接口的内容,请查看本文(披露:我是作者;)) https://nullbeans.com/the-java-comparable-interface-automatic-sort-of-collections/


0

如果您只有一个字符串属性路径要排序,您还可以使用Spring的PropertyComparator

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

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


-1

请在此处提供答案,而不是提供链接。链接可能会失效,从而使您的答案无用。 - Anurag Tripathi

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