按日期对ArrayList中的对象进行排序?

188

我发现的每个例子都是按字母顺序排列,而我需要按日期对元素进行排序。

我的ArrayList包含对象,其中一个datamember是DateTime对象。 在DateTime上,我可以调用以下函数:

lt() // less-than
lteq() // less-than-or-equal-to

那么,为了进行比较,我可以做这样的事情:

if(myList.get(i).lt(myList.get(j))){
    // ...
}

在if块中我应该做什么?


3
我已经发布了解决方案,但如果你想了解排序算法的话,你应该阅读一些关于排序算法的内容(如冒泡排序、归并排序、快速排序等)。 - helios
谢谢,我会看一下这些内容的,我对排序一无所知。 - user393964
在这个帖子中可以找到几个有用的Java 1.8解决方案:https://dev59.com/rVoV5IYBdhLWcg3wXNo9 - lradacher
你可以在这里找到升序和降序的答案:https://dev59.com/zqPia4cB1Zd3GeqPxFmQ#66772568 - David Kariuki
14个回答

477

您可以使您的对象可比较:

public static class MyObject implements Comparable<MyObject> {

  private Date dateTime;

  public Date getDateTime() {
    return dateTime;
  }

  public void setDateTime(Date datetime) {
    this.dateTime = datetime;
  }

  @Override
  public int compareTo(MyObject o) {
    return getDateTime().compareTo(o.getDateTime());
  }
}

然后您可以通过调用以下方法进行排序:

Collections.sort(myList);

但有时您不想更改自己的模型,例如当您想要按多个不同属性进行排序时。在这种情况下,可以即时创建比较器:

Collections.sort(myList, new Comparator<MyObject>() {
  public int compare(MyObject o1, MyObject o2) {
      return o1.getDateTime().compareTo(o2.getDateTime());
  }
});

然而,上述代码仅在您确定dateTime在比较时不为null才有效。为了避免NullPointerException,最好也处理null情况:

public static class MyObject implements Comparable<MyObject> {

  private Date dateTime;

  public Date getDateTime() {
    return dateTime;
  }

  public void setDateTime(Date datetime) {
    this.dateTime = datetime;
  }

  @Override
  public int compareTo(MyObject o) {
    if (getDateTime() == null || o.getDateTime() == null)
      return 0;
    return getDateTime().compareTo(o.getDateTime());
  }
}

或者在第二个例子中:

Collections.sort(myList, new Comparator<MyObject>() {
  public int compare(MyObject o1, MyObject o2) {
      if (o1.getDateTime() == null || o2.getDateTime() == null)
        return 0;
      return o1.getDateTime().compareTo(o2.getDateTime());
  }
});

1
好的回答。为什么需要包含没有空值检查的版本?有什么优势吗?如果正确的方式是第二种,那么你只能包含它并使重要信息更具吸引力。 - amotzg
18
两个原因——简单和快速失败。你希望代码尽可能简单,并且如果你确定你的属性不应该为null,那么当你遇到null时你希望你的代码尽快失败,而不是传递无效数据并进一步破坏从引入无效数据的地方更远的位置。 - Domchi
3
如果 o1 或 o2 为 null,则返回 0;// 这行代码可能会导致 bug,因为返回 0 意味着它们相等。 - tanyehzheng
@tanyehzheng,没错,这很容易让人产生误解,但请注意,.compareTo() 和 .equals() 是有区别的,前者用于排序,后者则不然。这取决于您在排序期间想如何处理空值。 - Domchi
1
你应该单独检查每个日期是否为空,并按所需排序(无论是将空值排序在序列开头还是结尾)。也就是说,如果一个日期为空,而另一个日期不为空,则返回1或-1。如果不这样做,那么空值将不会被排序,而是保留在排序之前列表中它们所在的位置。 - droozen
你可以在这里找到升序和降序的答案:https://dev59.com/zqPia4cB1Zd3GeqPxFmQ#66772568 - David Kariuki

114
自Java 8起,List接口提供了sort方法。结合lambda表达式,最简单的解决方案是:
// sort DateTime typed list
list.sort((d1,d2) -> d1.compareTo(d2));
// or an object which has an DateTime attribute
list.sort((o1,o2) -> o1.getDateTime().compareTo(o2.getDateTime()));
// or like mentioned by Tunaki
list.sort(Comparator.comparing(o -> o.getDateTime()));

反向排序

Java 8还提供了一些方便的方法进行反向排序。

//requested by lily
list.sort(Comparator.comparing(o -> o.getDateTime()).reversed());

11
更好的写法是 list.sort(Comparator.comparing(o -> o.getDateTime())); - Tunaki
40
这样怎么样:list.sort(Comparator.comparing(MyObject::getDateTime)) - whitebrow
1
@Tunaki 如何进行反向排序? - lily
1
@lily,Collections.sort(list, Collections.reverseOrder()); - sanghavi7
5
为了确保大家理解一致,例如这样的示例代码: list.sort(Comparator.comparing(MyObject::getDateTime)); 将会使最早的日期在第一个位置,最晚的日期在最后一个位置。如果您想要相反的顺序,请按照上面所示进行反转。 - Oliver

19

你可以使用Collections.sort方法。它是一个静态方法。你需要传递给它列表和一个比较器。它使用修改后的归并排序算法对列表进行排序。这就是为什么你必须传递一个比较器来进行比较。

Collections.sort(myList, new Comparator<MyObject> {
   public int compare(MyObject o1, MyObject o2) {
      DateTime a = o1.getDateTime();
      DateTime b = o2.getDateTime();
      if (a.lt(b)) 
        return -1;
      else if (a.lteq(b)) // it's equals
         return 0;
      else
         return 1;
   }
});

请注意,如果myList是可比较类型(实现了Comparable接口的类型),例如Date、Integer或String,您可以省略比较器,使用自然排序。


1
它执行完毕后会返回myList或类似的东西吗? - user393964
它修改了myList。因此,当它完成时,它已排序。 - helios
@Sled:http://download.oracle.com/javase/6/docs/api/java/util/Collections.html#sort(java.util.List, java.util.Comparator) - helios

14
list.sort(Comparator.comparing(o -> o.getDateTime()));

在我看来,使用Java 8 Lambda的最佳答案是Tunaki提供的。


8

假设有一个名为MyObject的对象,其中包含一种叫做getDateTime()的方法用于获取日期时间。你可以通过以下方式,对包含MyObject元素的ArrayList按照DateTime对象进行排序:

Collections.sort(myList, new Comparator<MyObject>() {
    public int compare(MyObject o1, MyObject o2) {
        return o1.getDateTime().lt(o2.getDateTime()) ? -1 : 1;
    }
});

如果我想根据当前系统时间进行排序怎么办? - User3

6

这是我的解决方法:

Collections.sort(MyList, (o1, o2) -> o1.getLastModified().compareTo(o2.getLastModified()));

希望能帮到你。

如何按日期反转它? - Zombie

6

这是我实现它的方法:

Mylist.sort(Comparator.comparing(myClass::getStarttime));

这对我来说就像魔法一样奏效。 - fulufhelo mudau

4

未来的读者,我认为这是最简单的解决方案,如果您的模型包含字符串类型的日期(例如"2020-01-01 10:00:00"),那么只需编写以下代码即可按照日期降序排列数据,从最新到最旧:

Collections.sort(messages, (o1, o2) -> o2.getMessageDate().compareTo(o1.getMessageDate()));

2

随着Java 1.8的推出,流在解决这类问题方面非常有用:

Comparator <DateTime> myComparator = (arg1, arg2) 
                -> {
                    if(arg1.lt(arg2)) 
                       return -1;
                    else if (arg1.lteq(arg2))
                       return 0;
                    else
                       return 1;
                   };

ArrayList<DateTime> sortedList = myList
                   .stream()
                   .sorted(myComparator)
                   .collect(Collectors.toCollection(ArrayList::new));

2

我发现这里所有的答案对于一个简单的问题来说都过于复杂了(至少是对于一个有经验的Java开发者来说,而我不是)。我曾经遇到过类似的问题,并偶然发现了这个(和其他)解决方案,但对于一个初学者来说,它们提供的指示并不够清晰。我的解决方案取决于你的日期在对象中的位置,而在这种情况下,日期是Object[]中第一个元素,其中dataVector是包含你的对象的ArrayList。

Collections.sort(dataVector, new Comparator<Object[]>() {
    public int compare(Object[] o1, Object[] o2) {
        return ((Date)o1[0]).compareTo(((Date)o2[0]));
    }
});

6
你的答案相较于其他答案来说更简单易懂或更正确吗?在我看来,例如WhiteFang32的答案非常相似且更为简洁。 - amotzg
离开了一段时间,所以没有看到回复,但是迟到总比不到好。我认为WhiteFang的回答中的简洁性是它对我(当时)缺乏经验的Java开发人员眼睛的缺点!我的回答中包含类型转换,这是决定性因素(至少在我当时的想法中)。你从哪里得出我的答案比其他答案更正确的说法呢?我想只是发泄一下..一切都被原谅了! - Nepaluz
o.getDateTime() 不是关于打字的问题,而是关于 OP 对包含在另一个对象中的 DateTime 对象的描述。如果只有 DateDateTime 对象是可比较的,那么一开始就不需要使用 Comparator - amotzg
我并不是想说你的答案不正确或者不好。我只是在寻找信息以帮助我更好地理解它。如果看起来有误解,我很抱歉。 - amotzg

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